更新:谢谢你们的支持,最近折腾了一个博客官网出来,方便你们系统阅读,后续会有更多内容和更多优化,猛戳这里查看前端
------ 如下是正文 ------webpack
本期的主题是this全面解析,本计划一共28期,每期重点攻克一个面试重难点,若是你还不了解本进阶计划,文末点击查看所有文章。git
若是以为本系列不错,欢迎点赞、评论、转发,您的支持就是我坚持的最大动力。github
上篇文章详细的分析了各类this的状况,看过以后对this的概念就很清晰了,没看过的去看看。web
咱们知道this绑定规则一共有5种状况:面试
其实大部分状况下能够用一句话来归纳,this老是指向调用该函数的对象。算法
可是对于箭头函数并非这样,是根据外层(函数或者全局)做用域(词法做用域)来决定this。跨域
对于箭头函数的this总结以下:浏览器
箭头函数不绑定this,箭头函数中的this至关于普通变量。安全
箭头函数的this寻值行为与普通变量相同,在做用域中逐级寻找。
箭头函数的this没法经过bind,call,apply来直接修改(能够间接修改)。
改变做用域中this的指向能够改变箭头函数的this。
eg. function closure(){()=>{//code }}
,在此例中,咱们经过改变封包环境closure.bind(another)()
,来改变箭头函数this的指向。
/** * 非严格模式 */
var name = 'window'
var person1 = {
name: 'person1',
show1: function () {
console.log(this.name)
},
show2: () => console.log(this.name),
show3: function () {
return function () {
console.log(this.name)
}
},
show4: function () {
return () => console.log(this.name)
}
}
var person2 = { name: 'person2' }
person1.show1()
person1.show1.call(person2)
person1.show2()
person1.show2.call(person2)
person1.show3()()
person1.show3().call(person2)
person1.show3.call(person2)()
person1.show4()()
person1.show4().call(person2)
person1.show4.call(person2)()
复制代码
空
白
占
位
符
正确答案以下:
person1.show1() // person1,隐式绑定,this指向调用者 person1
person1.show1.call(person2) // person2,显式绑定,this指向 person2
person1.show2() // window,箭头函数绑定,this指向外层做用域,即全局做用域
person1.show2.call(person2) // window,箭头函数绑定,this指向外层做用域,即全局做用域
person1.show3()() // window,默认绑定,这是一个高阶函数,调用者是window
// 相似于`var func = person1.show3()` 执行`func()`
person1.show3().call(person2) // person2,显式绑定,this指向 person2
person1.show3.call(person2)() // window,默认绑定,调用者是window
person1.show4()() // person1,箭头函数绑定,this指向外层做用域,即person1函数做用域
person1.show4().call(person2) // person1,箭头函数绑定,
// this指向外层做用域,即person1函数做用域
person1.show4.call(person2)() // person2
复制代码
最后一个person1.show4.call(person2)()
有点复杂,咱们来一层一层的剥开。
var func1 = person1.show4.call(person2)
,这是显式绑定,调用者是person2
,show4
函数指向的是person2
。func1()
,箭头函数绑定,this指向外层做用域,即person2
函数做用域首先要说明的是,箭头函数绑定中,this指向外层做用域,并不必定是第一层,也不必定是第二层。
由于没有自身的this,因此只能根据做用域链往上层查找,直到找到一个绑定了this的函数做用域,并指向调用该普通函数的对象。
此次经过构造函数来建立一个对象,并执行相同的4个show方法。
/** * 非严格模式 */
var name = 'window'
function Person (name) {
this.name = name;
this.show1 = function () {
console.log(this.name)
}
this.show2 = () => console.log(this.name)
this.show3 = function () {
return function () {
console.log(this.name)
}
}
this.show4 = function () {
return () => console.log(this.name)
}
}
var personA = new Person('personA')
var personB = new Person('personB')
personA.show1()
personA.show1.call(personB)
personA.show2()
personA.show2.call(personB)
personA.show3()()
personA.show3().call(personB)
personA.show3.call(personB)()
personA.show4()()
personA.show4().call(personB)
personA.show4.call(personB)()
复制代码
空
白
占
位
符
正确答案以下:
personA.show1() // personA,隐式绑定,调用者是 personA
personA.show1.call(personB) // personB,显式绑定,调用者是 personB
personA.show2() // personA,首先personA是new绑定,产生了新的构造函数做用域,
// 而后是箭头函数绑定,this指向外层做用域,即personA函数做用域
personA.show2.call(personB) // personA,同上
personA.show3()() // window,默认绑定,调用者是window
personA.show3().call(personB) // personB,显式绑定,调用者是personB
personA.show3.call(personB)() // window,默认绑定,调用者是window
personA.show4()() // personA,箭头函数绑定,this指向外层做用域,即personA函数做用域
personA.show4().call(personB) // personA,箭头函数绑定,call并无改变外层做用域,
// this指向外层做用域,即personA函数做用域
personA.show4.call(personB)() // personB,解析同题目1,最后是箭头函数绑定,
// this指向外层做用域,即改变后的person2函数做用域
复制代码
题目一和题目二的区别在于题目二使用了new操做符。
使用 new 操做符调用构造函数,实际上会经历一下4个步骤:
- 建立一个新对象;
- 将构造函数的做用域赋给新对象(所以this就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象。
依次给出console.log输出的数值。
var num = 1;
var myObject = {
num: 2,
add: function() {
this.num = 3;
(function() {
console.log(this.num);
this.num = 4;
})();
console.log(this.num);
},
sub: function() {
console.log(this.num)
}
}
myObject.add();
console.log(myObject.num);
console.log(num);
var sub = myObject.sub;
sub();
复制代码
答案有两种状况,分为严格模式和非严格模式。
TypeError: Cannot read property 'num' of undefined
解答过程:
var num = 1;
var myObject = {
num: 2,
add: function() {
this.num = 3; // 隐式绑定 修改 myObject.num = 3
(function() {
console.log(this.num); // 默认绑定 输出 1
this.num = 4; // 默认绑定 修改 window.num = 4
})();
console.log(this.num); // 隐式绑定 输出 3
},
sub: function() {
console.log(this.num) // 由于丢失了隐式绑定的myObject,因此使用默认绑定 输出 4
}
}
myObject.add(); // 1 3
console.log(myObject.num); // 3
console.log(num); // 4
var sub = myObject.sub;// 丢失了隐式绑定的myObject
sub(); // 4
复制代码
内容来自评论区:【进阶3-1期】JavaScript深刻之史上最全--5种this绑定全面解析
分别给出console.log输出的内容。
var obj = {
say: function () {
function _say() {
console.log(this);
}
console.log(obj);
return _say.bind(obj);
}()
}
obj.say()
复制代码
进阶系列文章汇总:github.com/yygmind/blo…,内有优质前端资料,以为不错点个star。
我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!