为什么要使用this
一句话就是,使用this
在某些场合下面可以简化代码。又到了举例子的时候了,在不使用this
的时候,需要传入上下文对象:
function identify(context){
return context.name.toUpperCase();
}
function speak(context){
var greeting = `Hello, I'm ${identify(context)}`;
console.log(greeting);
}
var me = { name: 'Armouy' };
var you = { name: 'sugarMei'};
speak(me);
speak(you);
如果使用了this
:
function identify(){
return this.name.toUpperCase();
}
function speak(){
var greeting = `Hello, I'm ${identify()}`;
console.log(greeting);
}
var me = { name: 'Armouy' };
var you = { name: 'sugarMei'};
speak.call(me);
speak.call(you);
当你的代码很复杂的时候,显示地传递上下文对象会很混乱,借助this
就会方便很多。但是this
的指向问题很容易让人产生混淆。
this的绑定规则
记住一句话,this实际上是在函数调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。这句话很好理解,谁调用了它,它就指向谁。this
的绑定规则一共有4种:
默认绑定
function foo(){
console.log(this.bar);
}
var bar = "bar";
foo(); // bar
foo
这种在调用方法,就是默认绑定。在非严格模式下,this
指向的是全局作用域;在严格模式下,指向的是undefined
。
隐式绑定
function foo(){
console.log(this.bar);
}
var bar = "bar";
var obj = {
bar: 'bar1',
foo: foo
}
obj.foo(); // bar1
obj.foo()
这种是隐式绑定,foo
成为了obj.foo
的方法,此时obj
调用了这个方法,this
就指向了obj
;所以this.bar
就是obj.bar
。
显示绑定
function foo(){
console.log(this.bar);
}
var bar = "bar";
var obj = {
bar: 'bar1'
}
foo.call(obj); // bar1
在这里如果通过call、apply或者bind
将调用的函数中的this
显示的绑定到了obj
上,所以this
指向的是obj
。打印的结果就是bar1
了。
new 绑定
function Foo(a){
this.a = a;
}
var foo = new Foo('a');
console.log(foo.a); // a
在new
调用函数,或者说发生构造函数调用时,会自动执行以下操作:
- 创建一个一个全新的对象:
var foo = {}
; - 把这个对象链接到原型对象上
foo.__proto__ = Foo.prototype
; - 这个新对象会绑定到函数调用的
this
:Foo.call(foo, a)
; - 返回对象。如果函数没有返回其他对象,那么new操作会自动返回这个新对象。
箭头函数
箭头函数不适用以上四种绑定规则,它是根据外层(函数或者全局)作用域来决定this
的。
对比这两个栗子的输出:
function Person(){
this.age = 0;
setTimeout(function () {
console.log(this.age); // 输出undefined
}, 1000);
}
var p = new Person();
function Person(){
this.age = 10;
setTimeout(()=> {
console.log(this.age); // 输出10
}, 1000);
}
var p = new Person();
总结
- 绑定的优先级: 箭头函数绑定 > new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定。
- 可以根据以下规则来判断是哪一种绑定:
- 函数是否在
new
中调用,是的话,this
绑定的是新创建的对象; - 函数是否是通过
call、bind或者apply
进行的显示绑定,是的话,this
执行的就是绑定的那个对象; - 函数是否在某个上下文对象中被调用,这就是隐形调用,
this
绑定的是那个上下文,例如:let obj = new Foo()
; - 如果都不是那就是默认绑定,
this
指向的是全局。
- 函数是否在