我们之前了解了函数调用中的this绑定的四条规则,你需要做的就是找到函数的调用位置并判断应当应用哪条规则。但是如果某个调用位置可以应用多条规则怎么办呢。这就是我们要介绍的了,接着来看吧!
毫无疑问,默认绑定是四条规则中优先级最低的,所以我们可以先不考虑它。
显式>隐式
function foo() {
console.log(this.a);
}
const obj1 = {
a: 2,
foo: foo,
};
const obj2 = {
a: 4,
};
obj1.foo.call(obj2)//4
new绑定>隐式
function Foo() {
this.a = "2";
}
const obj = {
a: 3,
Foo: Foo,
};
const person = new obj.Foo();
console.log(person.a); //2
//new > 隐式
new绑定>显式
function foo(a) {
this.a = a;
}
var obj1 = {};
var bar = foo.bind(obj1); //将this绑定到obj1
bar(2);
console.log(obj1.a); //2
var baz = new bar(3);
console.log(obj1.a); //2 ???
console.log(baz.a); //3
//修改了硬绑定到obj1的this
这里和我们之前说的不一样,因为this已经硬绑定到obj1了,但是new bar(3)后本来应该是变成了3的却还是2!我丢,这我们之前说的有点不一样啊,不是硬绑定就不可以改this了嘛(其实我也还没想出来,想到后会更新本篇文章!)。
综上所述,优先级:new绑定>显式绑定>隐式绑定>默认绑定
判断this的方法
- 函数是否在new中调用,如果是的话,this绑定的就是新创建的对象。var bar=new Bar()
- 函数是否通过call,apply(显式绑定)或者硬绑定?如果是的话,this绑定就是指定的对象。
- 函数是否在某个上下文中调用(隐式绑定)?如果是的话,this绑定的就是那个上下文对象。
- 如果都不是的话,使用默认绑定,如果在严格模式下,就绑定到undefiend,否则绑定到全局对象。
上述的方法只能从从上往下去判断,并且这些方法对于正常的函数调用来说已经够了,除了一些例外!请移步上一篇文章!
箭头函数=>
一个逍遥在this绑定规则外的就是ES6的箭头函数了!它并不适用this的四种规则,而是根据外层(函数或者全局)作用域来决定this。
function foo() {
return (a) => {
//this继承自foo
console.log(this.a);
};
}
const obj1 = {
a: 2,
};
const obj2 = {
a: 3,
};
const bar = foo.call(obj1);
bar.call(obj2); //2 不是3!
在声明bar的时候,把foo的this绑定到obj1 this也会绑定到obj1,在执行返回的箭头函数的时候 不受显式绑定限制,箭头函数的绑定无法修改,( new也不行!)
箭头函数最常用于回调函数中,例如事件处理器或者定时器:
function foo() {
setTimeout(() => {
console.log(this.a);
}, 300);
}
const obj = {
a: 2,
};
foo.call(obj); //2
箭头函数可以像bind(…)一样确保函数的this被绑定到指定对象,此外,其重要性还体现它更常见的词法作用域取代了传统的this机制,实际上在ES6之前我们就已经使用了一种几乎和箭头函数完全一样的模式
const obj = {
a: 2,
};
function bar() {
const that = this;
setTimeout(function () {
console.log(that.a);
}, 200);
}
bar.call(obj); //2
虽然that=this和箭头函数看起来都可以取代bind,但是从本质上来说,它们想替代的是this的机制。