this指向"死记硬背"定律
- 在函数体中,非显示或隐式地简单调用函数时,在严格模式下,函数内的
this
会被绑定到undefined
上,在非严格模式下则会被绑定到全局对象window/global
上 - 一般使用
new
方法调用构造函数时,构造函数中的this
会被绑定到新创建的对象上 - 显示的通过
apply/call/bind
绑定this
指向指定的参数对象上 - 一般通过上下文对象调用函数时,函数内部的
this
绑定到该对象上 - 在箭头函数中,
this
指向外层this
的指向位置
全局环境中的this
js
function fn1() {
console.log(this); // window
}
function fn2() {
"use strict";
console.log(this); // undefined
}
fn1();
fn2();
函数在浏览器全局环境中被简单调用,在严格模式下this
指向为undefined
。在非严格模式下this
指向window
对象
js
const obj = {
bar: 10,
foo() {
console.log(this);
},
};
const fn = obj.foo;
fn(); //window
上述代码运行结果为window
对象,因为最终foo
函数被简单的在全局环境中被调用,所以this
指向window
js
const obj = {
bar: 10,
foo() {
console.log(this);
},
};
obj.foo(); // { bar: 10, foo: [Function: foo] }
在不考虑显示绑定的情况下:上述代码通过对象obj
调用foo
函数,所以函数内部的this
指向obj
对象,所以如果函数中的this
是被上一级的对象调用的,则this
指向的就是上一级对象。否则指向window
对象
通过bind
,apply
,call
,改变this
指向
它们都是用来改变函数this
指向,apply
,call
是直接进行相关函数的调用;bind
不会指向相关函数,而是返回一个新的函数,这个函数的this
指向已经绑定,开发者可以手动调用。
js
const obj = {
bar: 10,
foo() {
console.log(this.bar);
},
};
const obj1 = {
bar: 20,
};
obj.foo.call(obj1); // 20
上述代码输出值20
,通过call
改变了foo
函数的this
指向
构造函数与this
js
function Fn() {
this.bar = 110;
}
const instance = new Fn();
console.log(instance.bar); // 110
上述代码输出值110
,表明通过new
操作符实例化构造函数,构造函数中的this
指向为实例对象。
箭头函数中的this
箭头函数中的this
,是由外层函数作用域或者全局作用域决定的。
js
const obj = {
bar: 10,
foo() {
setTimeout(function () {
console.log(this.bar);
});
},
};
obj.foo(); // undefined
setTimeout
函数传入一个匿名函数其this指向为window
,作用上述代码打印undefined
,如果希望setTimeout
中的回调函数中this
指向为obj
则可以将匿名函数改为箭头函数,因为箭头函数中的this
指向是根据其外层函数的this
指向所决定。
js
const obj = {
bar: 10,
foo() {
setTimeout(() => {
console.log(this.bar);
});
},
};
obj.foo(); // 10
this
的优先级
显示绑定和隐式绑定的优先级
js
const obj = {
bar: 10,
foo() {
console.log(this.bar);
},
};
const obj1 = {
bar: 20,
};
obj.foo.call(obj1); // 20
上述代码输出为20
,可以知道显示绑定优先级高于隐式绑定优先级
new
操作符和显示绑定的优先级
js
function fun(a) {
this.a = a;
}
const obj3 = {};
const bar = fun.bind(obj3);
bar(100);
console.log(obj3.a); // 100
const baz = new bar(300);
console.log(baz.a); // 300
console.log(obj3); // { a: 100 }
上述代码可以看出,new
操作符在 fun.bind()
之后绑定到obj3
上之后,通过new bar()
之后改变了bar
h函数的this
指向。所以new
操作符的优先级高于显示绑定优先级
注意:
如果显示绑定的函数为箭头函数,箭头函数中的this
不会被改变,按照其规则进行指向,这里我们将上例进行修改:
js
fun = (a) => {
this.a = a;
};
const obj3 = {};
const bar = fun.bind(obj3);
bar(100);
console.log(obj3.a); // undefined
console.log(window.a); // 100