这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
在我们平常的学习工作中,经常会遇到this ,那么到底什么是this你真的搞懂了吗?在JavaScript中,this是一个很复杂的关键字,也是特别烦人的,很多人都会被this搞的晕头转向。下面这篇文章我们就来介绍一下this到底是什么?
什么是this?
this 是JavaScript中的一个关键词,在JavaScript中,this不是固定不变的,它会随着执行环境的改变而改变。实际上this就是一个指针,它最终指向调用函数的那个对象。 通常this的指向分为很多种情况,下面我们一一 来介绍:
1. 默认情况(默认绑定)
默认的this
console.log(this); // window,这里不区分严格模式和非严格模式,都是指向window
在默认情况下,this指向window
函数中的this
"use strict";
function fn(){
console.log(this);//非严格模式指向window,严格模式指向undefined
}
fn();
在严格模式下,函数中的this是undefined,但是在非严格模式下,函数中的this指向window
2. 隐式绑定
对象方法中的this
1.如果函数调用是在一个对象上触发的,即存在上下文对象,那么这个函数中的this指向调用函数的对象
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'jack',
sayHi: sayHi
}
var name = 'bob';
person.sayHi(); // Hello,jack
2.需要注意的是,在对象的属性链中,只有最后一个属性会影响函数中的this。(就近原则)
function sayHi(){
console.log('Hello,', this.name);
}
var person2 = {
name: 'jack',
sayHi: sayHi
}
var person1 = {
name: 'bob',
friend: person2
}
person1.friend.sayHi();// Hello,jack
回调函数中的this
1.普通回调函数中
function fn(f){
f();
}
function fn1(){
console.log(this);
}
fn(fn1);
在这个例子中,fn1被作为回调函数调用,回调函数中的this指向和默认绑定的一样,在非严格模式下指向window,在严格模式下指向undefined。
promise中的.then回调也属于普通回调,同样遵循此规则。
2.特殊回调函数(定时器回调函数)
setTimeout(function(){
console.log(this);
});
setInterval(() => {
console.log(this);
},1000);
对于定时器中的回调,不管是在严格模式还是非严格模式下,this稳定指向window。
3.数组遍历方法中的this
var arr=[1,2];
arr.forEach(function(){
console.log(this);
})
在数组的遍历方法中,传入的方法其实也是回调函数,如果在这个方法中不指定替代this对象时,同样非严格模式指向window,严格模式指向undefined。
4.事件回调函数
document.addEventListener("click",clickhandler);
function clickhandler(e){
console.log(this);//侦听事件的对象
}
在绑定事件的回调函数中,回调函数中的this指向被侦听事件的对象。上面的例子中,this就是document对象。
5.使用arguments关键字调用回调函数
function fn(){
arguments[0]()
}
function fn1(){
console.log(this);//this指向fn中arguments
}
fn(fn1);
当在函数中通过arguments调用回调函数时,回调函数中的this指向Arguments对象。
3.call、apply、bind(显式绑定)
call、apply、bind都可以通过传递参数来改变this的指向。
相同点:
-
都可以通过传参改变this的指向,传递的第一个参数就是this
-
如果第一个参数传null或undefined,那么这些值都会被忽略,this的指向就会走默认绑定规则,非严格模式下指向window
不同点:
-
传参不同:
call( this,pra1,pra2,pra3 ),call传递参数是一个一个传递,而apply第二个参数是一个数组apply( this,[pra1,pra2,pra3] ) -
call和apply在执行时会直接调用函数,而bind不会调用函数。
document.onclick = fn.call(obj); // this改变为obj了,但是绑定的时候立即执行,当触发点击事件的时候执行的是fn的返回值undefined
document.onclick = fn.bind(obj); // bind会把fn中的this预处理为obj,此时fn没有执行,当点击的时候才会把fn执行
4. new 绑定
在JavaScript中,构造函数只是使用new操作符时被调用的普通函数,不属于某个类,也不会实例化一个类。所有的函数都可以通过new来调用,称为构造函数调用。
当使用new来调用函数的时候会自动执行以下操作:
1. 创建一个空对象,构造函数中的this指向这个空对象
2. 执行原型连接 target.__proto__ = constructor.prototype
3. 执行构造函数方法,属性和方法都被添加到this指向的对象上
4. 如果构造函数中没有返回其他的对象,那么就返回this(即创建的这个新对象);否则,返回构造函数中返回的对象。
function Fn(){
this.name = 'jack';
};
let person = new Fn();
person.name//jack
上面这个例子中,这个过程就称为构造调用,this将指向新创建的对象person;
5.箭头函数绑定
箭头函数是ES6新增的,它和普通函数有一些区别,箭头函数没有自己的this,它的this继承于当前函数执行上下文中的this。
在使用箭头函数时,有几点需要注意:
1. 函数中的this,继承的是外层代码块中的this。
2. 箭头函数不能作为构造函数使用new调用,否则会抛出错误。TypeError: fn is not a constructor
3. 不可以使用arguments对象,该对象在函数体内不存在。如果要用可以使用rest参数代替。
Q:什么是rest参数? rest 顾名思义,就是剩余的。下面看两个例子就懂了。
// 例1
let fn = (...vals) => {
console.log(vals); // [1, 2, 3]
}
fn(1, 2, 3);
// 例2
let fn = (name, ...vals) => {
console.log(name); // jack
console.log(vals); // [1, 2, 3]
}
fn('jack', 1, 2, 3);
4. 不可以使用yield命令,所有箭头函数不能用作Generator函数。
5. 箭头函数没有自己的this,所以不能用call、apply、bind这些方法去改变this的指向。
总结
this绑定无非就是分为几种场景:默认绑定、隐式绑定、显示绑定、new绑定、箭头函数绑定
-
默认绑定 默认绑定可以理解为函数调用时无任何调用前缀的场景 ,默认绑定的情况下,this指向全局对象window(非严格模式),this指向undefined(严格模式)。
-
隐式绑定 如果函数调用时,前面存在调用它的对象,那么this就会隐式的绑定到这个对象上。如果函数调用前存在多个对象,this指向距离调用自己最近的对象
-
显示绑定 显示绑定就是通过call、apply、bind方法改变this指向。这三个方法传递的第一个参数就是最终的this指向。如果第一个参数是null或undefined,那么this将采用默认绑定的规则,指向全局对象。
-
new绑定 使用new绑定时,this指向新创建的那个对象。
-
箭头函数 箭头函数中没有this,箭头函数的this指向取决于外层作用域中的this,外层作用域或函数的this指向谁,箭头函数中的this便指向谁。
看到最后,是不是感觉对this有了一定了解了,下面就在例题中检测一下吧。
例题
- 例1
var obj = {
a: 10,
c: 50,
b: {
a: 0,
c: this.a,
run: function () {
console.log(this.c);
}
}
}
obj.b.run();
- 例2
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function (fn) {
fn();
arguments[0]();
}
}
obj.method(fn, 1);
- 例3
var name = '222';
var a = {
name: '111',
say: function () {
console.log(this.name)
}
}
var b = {
name: '333',
say: function (fn) {
fn()
}
}
a.say()
b.say(a.say)
- 例4
window.number = 2;
var obj = {
'number': 3,
'db1': (function () {
console.log(this);
this.number *= 4;
return function () {
console.log(this);
this.number *= 5;
}
})()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);
本文参考: 作者:刘小夕 链接:juejin.cn/post/684490…来源:掘金