每个函数的this是在函数执行时绑定的,完全取决于函数的调用位置(函数执行时地方)。
我把js中的this指向分为以下5大类
默认绑定
默认绑定时是把this绑定在window上;
如果使用严格模式,则会绑定到undefined上
function foo(){
console.log(this.a)
}
var a = 2
foo() // 2
这里的this就绑定在window上,如果使用严格模式,则this指向的是undefined
function foo(){
'use strict'
console.log(this.a) // typeError:this is undefined
}
var a = 2
foo() // 2
隐式绑定
隐式绑定指的是在调用的位置是否有上下文关系(是否被某个对象所包含),这种情况下谁调用指向谁
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo: foo
}
obj.foo() // 2
// 由于调用者是obj这个对象,所以foo中的this.a指向obj.a
一个多级对象在调用方法时,this绑定在离他最近的那个对象上
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo: foo
}
var obj1 = {
a:3,
obj:obj
}
obj1.obj.foo() // 2
此外,隐式绑定有一种特殊情况,就是隐式丢失
当并不是直接调用某个函数或方法时,这时候会出现this绑定丢失的情况。
以下是几种绑定丢失的情况
- 给函数起别名
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo: foo
}
var baz = obj.foo
var a = 'baz'
baz() // baz
// baz函数实际上引用的是foo函数本身,因此这时候使用了默认绑定
- 函数作为另一个函数的回调
function foo(){
console.log(this.a)
}
var obj = {
a:2,
foo: foo
}
function doFoo(fn){
fn()
}
var a = 'baz'
doFoo(obj.foo) // baz
显式绑定
显示绑定是指通过call/apply/bind绑定的this。
他们的区别主要如下:
- call: 第一个参数是被绑定的this对象,之后依次写要传的函数参数
- apply: 第一个参数是被绑定的this对象,之后是一个数组,需要的参数传入这个数组
- bind:bind返回的是一个函数,需要加()再次执行
new绑定(构造函数绑定)
通过 new 构造的函数实例,this绑定在当前实例上
function Foo(a){
this.a = a
}
var foo = new Foo(2)
console.log(foo.a) // 2
关于构造函数new的过程,主要分为以下四步:
1.创建一个对象
2.构造这个对象的prototype等属性
3.将这个对象绑定到this
4.返回这个对象
箭头函数中的this
箭头函数没有自己的 this,当在内部使用了 this时,它会指向最近一层作用域内的 this,箭头函数的this在定义时就确定了。
var name = 'xiaohong';
var obj = {
name: 'xm',
sayName: () => {
console.log(this.name)
}
}
obj.sayName() // xiaohong
此时的箭头函数和sayName是同级的,它属于obj,由于箭头函数没有this,所以它的this指向离它最近的作用域的this,即指向window。
var obj = {
name: 'xm',
sayName: function(){
return () => {
console.log(this.name);
}
}
}
obj.sayName()() //xm
由于箭头函数没有自己的 this,当在内部使用了 this时,它会指向最近一层作用域内的 this,箭头函数的最近一层的作用域为obj内,所以它的this指向obj
var obj = {
name: 'xm',
sayName: function(){
return () => {
return () => {
return () => {
console.log(this.name);
};
};
};
}
}
obj.sayName()()()() // xm
以上函数定义了三个箭头函数,由于三个箭头函数都不存在this,所以它的this指向了离箭头函数最近的obj.