持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
回顾
先来回顾一下this的绑定规则
- 默认绑定
- 隐式绑定
- 显示绑定
- new关键字绑定
特殊情况
- 箭头函数的this
- 规则外的this绑定
它们的优先级顺序如下,隐式绑定大于默认绑定,显式绑定大于隐式绑定,new关键字大于隐式绑定,new关键字大于显示绑定中的bind
详见 重学javaScript (十二)| this绑定规则的优先级 - 掘金 (juejin.cn)
几道题目
我们按照学习的规则来看几道面试题巩固一下
- 题目1
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss();
person.sayName();
(person.sayName)();
(b = person.sayName)();
}
sayName();
先来看执行结果
解析:
- sss() 这一行,因为是默认绑定,所以打印结果为
window - person.sayName() 这一行,是隐式绑定到了person上,所以打印结果是
person - (person.sayName)() 这一行跟 person.sayName() 等同,也是隐式绑定到了person上,所以打印结果是
person - (b = person.sayName)(); 这一行相当于执行b() 是默认绑定,就是打印
window
- 题目2
var name = 'window'
var person1 = {
name: 'person1',
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function () {
return function () {
console.log(this.name)
}
},
foo4: function () {
return () => {
console.log(this.name)
}
}
}
var person2 = { name: 'person2' }
person1.foo1();
person1.foo1.call(person2);
person1.foo2();
person1.foo2.call(person2);
person1.foo3()();
person1.foo3.call(person2)();
person1.foo3().call(person2);
person1.foo4()();
person1.foo4.call(person2)();
person1.foo4().call(person2);
来看下运行结果
解析:
- person1.foo1() 这一行就是隐式绑定,打印结果是
person1 - person1.foo1.call(person2) 这一行是做了显式绑定,打印结果是
person2 - person1.foo2() 这一行的foo2是箭头函数,它是不绑定this的,this指向就是父级作用域,它的父级作用域是window,所以打印
window - person1.foo2.call(person2) 这一行foo2是箭头函数,所以打印
window - person1.foo3()() 这一行其实是默认绑定,所以打印
window - person1.foo3.call(person2)() 这一行其实是默认绑定,所以打印
window - person1.foo3().call(person2) 这一行是显示绑定,所以打印
person2 - person1.foo4()() 这一行 foo4是箭头函数,找它父级作用域,所以打印
person1 - person1.foo4.call(person2)() 这一行 foo4是箭头函数,找它父级作用域,父级函数已经经过显式绑定,所以打印
person2 - person1.foo4().call(person2) 这一行 foo4是箭头函数,找它父级作用域,所以打印
person1
- 题目3
var name = 'window'
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1()
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)
person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)
来看下运行结果
解析:
- person1.foo1() 这一行就是隐式绑定,打印结果是
person1 - person1.foo1.call(person2) 这一行是做了显式绑定,打印结果是
person2 - person1.foo2() 这一行的foo2是箭头函数,它是不绑定this的,this指向就是父级作用域,它的父级作用域是person1,所以打印
person1 - person1.foo2.call(person2) 这一行foo2是箭头函数,所以打印
person1 - person1.foo3()() 这一行其实是默认绑定,所以打印
window - person1.foo3.call(person2)() 这一行其实是默认绑定,所以打印
window - person1.foo3().call(person2) 这一行是显示绑定,所以打印
person2 - person1.foo4()() 这一行 foo4是箭头函数,找它父级作用域,所以打印
person1 - person1.foo4.call(person2)() 这一行 foo4是箭头函数,找它父级作用域,父级函数已经经过显式绑定,所以打印
person2 - person1.foo4().call(person2) 这一行 foo4是箭头函数,找它父级作用域,所以打印
person1
- 题目4
var name = 'window'
function Person (name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)
person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)
解析:
- person1.obj.foo1()() 这一行其实是默认绑定,所以打印
window - person1.obj.foo1.call(person2)() 这一行其实是默认绑定,所以打印
window - pperson1.obj.foo1().call(person2) 这一行其实是显式绑定,所以打印
person2 - person1.obj.foo2()() 这一行foo2是箭头函数,所以找父级作用域,打印
obj - person1.obj.foo2.call(person2)() 这一行foo2是箭头函数,所以找父级作用域,父级指向已改变,打印
person2 - person1.obj.foo2().call(person2) 这一行foo2是箭头函数,call不起作用,所以找父级作用域,打印
obj