咱们知道this绑定规则一共有5种状况:前端
其实大部分状况下能够用一句话来归纳,this老是指向调用该函数的对象。webpack
可是对于箭头函数并非这样,是根据外层(函数或者全局)做用域(词法做用域)来决定this。git
对于箭头函数的this总结以下:github
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)()
空web
白面试
占算法
位跨域
符浏览器
正确答案以下:安全
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()
从这两套题,从新认识JS的this、做用域、闭包、对象
进阶系列文章汇总:https://github.com/yygmind/blog,内有优质前端资料,欢迎领取,以为不错点个star。
我是木易杨,网易高级前端工程师,跟着我每周重点攻克一个前端面试重难点。接下来让我带你走进高级前端的世界,在进阶的路上,共勉!