咱們知道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。
我是木易楊,網易高級前端工程師,跟着我每週重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!