JavaScript 判断函数的this 绑定
1.函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
function fun(){ this.age = 23; } var obj = new fun(); console.log(window.age); //undefined console.log(obj.age); //23
2.函数是否通过 call、apply、bind(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。
var obj = {}; function fun(){ console.log(this === obj); } fun(); //false fun.apply(obj); //true fun.call(obj); //true fun.bind(obj)(); //true
3.函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。
var obj = { fun : function(){ console.log(this === obj); } }; obj.fun(); //true
对象属性引用链中只有最顶层或者说最后一层会影响调用位置。
function fun(){ console.log(this === obj1); } var obj1 = { fun : fun } var obj2 = { obj1 : obj1 } var obj3 = { obj2 : obj2 } obj3.obj2.obj1.fun(); //true
4.如果都不是的话,使用(默认绑定)。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。
function fun(){ console.log(this === window); } fun(); //true function fun(){ 'use strict'; console.log(this === undefined); } fun(); //true
对于默认绑定来说,决定 this 绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。如果函数体处于严格模式,this 会被绑定到 undefined,否则 this 会被绑定到全局对象。
function fun(){ console.log(this === window); } (function(){ 'use strict'; fun(); })(); //true
如果某个函数的调用位置应用了多条规则,那么将按照:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定 的优先级来决定哪条规则会生效。
注意:
一、有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑定,你可以使用一个 DMZ 对象,比如 ø = Object.create(null) ,以保护全局对象。
二、window.setTimeout()和window.setInterval()的函数中的this有些特殊,里面的this默认是window对象
ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。
箭头函数的特性一:默认绑定外层this(因为箭头函数默认不会使用自己的this,而是会和外层的this保持一致,最外层的this就是window对象。)
const obj = { a: function() { console.log(this) } } obj.a() //打出的是obj对象 //箭头函数 const obj = { a: () => { console.log(this) } } obj.a() //打出来的是window
箭头函数的特性二:不能用call方法修改里面的this
const obj = { a: () => { console.log(this) } } obj.a.call('123') //打出来的结果依然是window对象 //上文我们说到window.setTimeout()中函数里的this默认是window,我们也可以通过箭头函数使它的this和外层的this保持一致 const obj = { a: function() { console.log(this) window.setTimeout(() => { console.log(this) }, 1000) } } obj.a.call(obj) //第一个this是obj对象,第二个this还是obj对象
多层对象嵌套里函数的this
const obj = { a: function() { console.log(this) }, b: { c: function() {console.log(this)} } } obj.a() // 打出的是obj对象, 相当于obj.a.call(obj) obj.b.c() //打出的是obj.b对象, 相当于obj.b.c.call(obj.b) //看看箭头函数 const obj = { a: function() { console.log(this) }, b: { c: () => {console.log(this)} } } obj.a() //没有使用箭头函数打出的是obj obj.b.c() //打出的是window对象!!
MDN官方文档里面描述箭头函数this定义的时候,描述的是“箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。",所以最后一个例子,打出window对象的原因,是window对象就是它的上一层this,而多层嵌套只是对象嵌套,这时候没有作用域链的嵌套。
浙公网安备 33010602011771号