摘要:最后重點(diǎn)理解結(jié)論箭頭函數(shù)的,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。輸出,箭頭函數(shù)不會(huì)綁定所以傳入指向無效。原因是,要徹底理解應(yīng)該是建立在已經(jīng)大致理解了中的執(zhí)行上下文,作用域作用域鏈,閉包,變量對(duì)象,函數(shù)執(zhí)行過程的基礎(chǔ)上。
本文共 2025 字,看完只需 8 分鐘概述
前面的文章講解了 JavaScript 中的執(zhí)行上下文,作用域,變量對(duì)象,this 的相關(guān)原理,但是我后來在網(wǎng)上看到一些例題的時(shí)候,依然沒能全做對(duì),說明自己有些細(xì)節(jié)還沒能掌握,本文就結(jié)合例題進(jìn)行深入實(shí)踐,討論函數(shù)在不同的調(diào)用方式 this 的指向問題。
老規(guī)矩,先給結(jié)論 1 和 結(jié)論2:
this 始終指向最后調(diào)用它的對(duì)象“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。
特別提示:
本文的例子,最好自己在瀏覽器控制臺(tái)中去試一遍,看完過兩天就會(huì)忘的,一定要實(shí)踐。
// 例 1 var name = "window"; function foo() { var name = "inner"; console.log(this.name); } foo(); // ?
輸出:
window
例 1 中,非嚴(yán)格模式,由于 foo 函數(shù)是在全局環(huán)境中被調(diào)用,this 會(huì)被默認(rèn)指向全局對(duì)象 window;
所以符合了我們的結(jié)論一:
this 始終指向最后調(diào)用它的對(duì)象二、一般函數(shù)和箭頭函數(shù)的對(duì)象調(diào)用
// 例 2 var name = "window"; var person = { name: "inner", show1: function () { console.log(this.name); }, show2: () => { console.log(this.name); } } person.show1(); // ? person.show2(); // ?
輸出:
inner
window
person.show1() 輸出 inner 沒毛病,person.show2() 箭頭函數(shù)為什么會(huì)輸出 window 呢。MDN 中對(duì) this 的定義是:
箭頭函數(shù)不綁定 this, 箭頭函數(shù)不會(huì)創(chuàng)建自己的this,它只會(huì)從自己的作用域鏈的上一層繼承this。
再看本文前面給的結(jié)論:
“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。
由于 JS 中只有全局作用域和函數(shù)作用域,箭頭函數(shù)在定義時(shí)的上一層作用域是全局環(huán)境,全局環(huán)境中的 this 指向全局對(duì)象本身,即 window。
三、call// 例 3 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
person2window
windowwindow
person2
windowperson1
person1
person2
上面 10 行打印,你對(duì)了幾個(gè)呢?
首先:
person1.show1() 和 person1.show1.call(person2) 輸出結(jié)果應(yīng)該沒問題,call 的作用就是改變了調(diào)用的對(duì)象 為 person2。
其次:
person1.show2(),person1.show2.call(person2),由于調(diào)用的是箭頭函數(shù),和本文例 2 中是一樣的,箭頭函數(shù)定義時(shí) this 指向的是上一層,也就是全局對(duì)象, 并且 箭頭函數(shù)不綁定自己的 this, 所以通過 call() 或 apply() 方法調(diào)用箭頭函數(shù)時(shí),只能傳遞參數(shù),不能傳遞新的對(duì)象進(jìn)行綁定。故打印的值都是 window。
進(jìn)而:
function foo () { return function () { console.log(this.name) } } foo()();
博客前面的文章有講過閉包,上面這段代碼也是典型的閉包運(yùn)用,可以看作:
function foo () { return function () { console.log(this.name) } } var bar = foo(); bar();
所以,很明顯,被返回的內(nèi)部函數(shù)其實(shí)是在全局環(huán)境下被調(diào)用的。回到前面看我們的結(jié)論 1,this 始終指向最后調(diào)用函數(shù)的對(duì)象,這句話的關(guān)鍵詞應(yīng)該是什么?我覺得應(yīng)該是 調(diào)用,什么時(shí)候調(diào)用,誰調(diào)用。
再回過頭來看:
person1.show3()() 輸出 window,因?yàn)閮?nèi)部函數(shù)在全局環(huán)境中被調(diào)用。
person1.show3().call(person2) 輸出 person2, 因?yàn)閮?nèi)部函數(shù)被 person2 對(duì)象調(diào)用了。
person1.show3.call(person2)() 輸出 window,也是因?yàn)閮?nèi)部函數(shù)在全局環(huán)境中被調(diào)用。
最后:
重點(diǎn)理解結(jié)論 2:
“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。
show4: function () { return () => console.log(this.name) }
這段代碼中,箭頭函數(shù)是在 外層函數(shù) show4 執(zhí)行后才被定義的。為什么?可以翻看我前面關(guān)于作用域鏈,執(zhí)行上下文,變量對(duì)象的文章,函數(shù)在進(jìn)入執(zhí)行階段時(shí),會(huì)先查找內(nèi)部的變量和函數(shù)聲明,將他們作為變量對(duì)象的屬性,關(guān)聯(lián)作用域鏈,并綁定 this 指向。
所以:
person1.show4()() 輸出 person1,因?yàn)橥獠亢瘮?shù)在執(zhí)行時(shí)的 this 為 person1, 此時(shí)定義了內(nèi)部函數(shù),而內(nèi)部函數(shù)為外部函數(shù)的 this。
person1.show4().call(person2) 輸出 person1,箭頭函數(shù)不會(huì)綁定 this, 所以 call 傳入 this 指向無效。
person1.show4.call(person2)() 輸出 person2,因?yàn)橥獠亢瘮?shù)在執(zhí)行時(shí)的 this 為 person2,此時(shí)定義了內(nèi)部函數(shù),而內(nèi)部函數(shù)為外部函數(shù)的 this。
四、構(gòu)造函數(shù)中的 this// 例 4 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
personBpersonA
personAwindow
personB
windowpersonA
personA
personB
例 4 和 例 3 大致一樣,唯一的區(qū)別在于兩點(diǎn):
構(gòu)造函數(shù)中 this 指向被創(chuàng)建的實(shí)例
構(gòu)造函數(shù),也是函數(shù),所以存在作用域,所以里面的箭頭函數(shù),它們的 this 指向,來自于上一層,就不再是全局環(huán)境 window, 而是構(gòu)造函數(shù) 的 this。
五、setTimeout 函數(shù)// 例 5 function foo(){ setTimeout(() =>{ console.log("id:", this.id) setTimeout(() =>{ console.log("id:", this.id) }, 100); }, 100); } foo.call({id: 111}); //
輸出:
111
111
注意一點(diǎn):
setTimeout 函數(shù)是在全局環(huán)境被 window 對(duì)象執(zhí)行的,但是 foo 函數(shù)在執(zhí)行時(shí),setTimtout 委托的匿名箭頭函數(shù)被定義,箭頭函數(shù)的 this 來自于上層函數(shù) foo 的調(diào)用對(duì)象, 所以打印結(jié)果才為 111;
// 例 6 function foo1(){ setTimeout(() =>{ console.log("id:", this.id) setTimeout(function (){ console.log("id:", this.id) }, 100); }, 100); } function foo2(){ setTimeout(function() { console.log("id:", this.id) setTimeout(() => { console.log("id:", this.id) }, 100); }, 100); } foo1.call({ id: 111 }); // ? foo2.call({ id: 222 }); // ?
輸出:
111
undefinedundefined
undefined
例 5 中已經(jīng)提到,setTimeout函數(shù)被 window 對(duì)象調(diào)用,如果
是普通函數(shù),內(nèi)部的 this 自然指向了全局對(duì)象下的 id, 所以為 undefined,如果是箭頭函數(shù),this 指向的就是外部函數(shù)的 this。
// 例 7 function foo() { return () => { return () => { return () => { console.log("id:", this.id); }; }; }; } var f = foo.call({id: 1}); var t1 = f.call({id: 2})()(); // var t2 = f().call({id: 3})(); // var t3 = f()().call({id: 4}); //
輸出:
1
1
1
這段代碼是為了鞏固我們的結(jié)論2:
“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。
foo.call({}) 在執(zhí)行時(shí),內(nèi)部的第一層箭頭函數(shù)才被定義
箭頭函數(shù)無法綁定 this, 所以 call 函數(shù)指定 this 無效
箭頭函數(shù)的 this 來自于上一層作用域(非箭頭函數(shù)作用域)的 this
總結(jié)有本書中有提到,當(dāng)理解 JavaScript 中的 this 之后,JavaScript 才算入門,我深以為然。
原因是,要徹底理解 this, 應(yīng)該是建立在已經(jīng)大致理解了 JS 中的執(zhí)行上下文,作用域、作用域鏈,閉包,變量對(duì)象,函數(shù)執(zhí)行過程的基礎(chǔ)上。
有興趣深入了解上下文,作用域,閉包相關(guān)內(nèi)容的同學(xué)可以翻看我之前的文章。
1:this、apply、call、bind
2: 從這兩套題,重新認(rèn)識(shí)JS的this、作用域、閉包、對(duì)象
3: 關(guān)于箭頭函數(shù)this的理解幾乎完全是錯(cuò)誤的
4: 深入JS系列
歡迎關(guān)注我的個(gè)人公眾號(hào)“謝南波”,專注分享原創(chuàng)文章。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98761.html
摘要:將元素作為對(duì)象的鍵,默認(rèn)鍵對(duì)應(yīng)的值為如果對(duì)象中沒有這個(gè)鍵,則將這個(gè)元素放入結(jié)果數(shù)組中去。 前言 數(shù)組去重在日常開發(fā)中的使用頻率還是較高的,也是網(wǎng)上隨便一抓一大把的話題,所以,我寫這篇文章目的在于歸納和總結(jié),既然很多人都在提的數(shù)組去重,自己到底了解多少呢。又或者是如果自己在開發(fā)中遇到了去重的需求,自己能想到更好的解決方案嗎。 這次我們來理一理怎么做數(shù)組去重才能做得最合適,既要考慮兼容性,...
摘要:第二問直接調(diào)用函數(shù),相當(dāng)于調(diào)用,那么與函數(shù)無關(guān)。第三問先執(zhí)行了函數(shù),然后調(diào)用函數(shù)的返回值對(duì)象的屬性函數(shù)。第四問再次調(diào)用函數(shù)時(shí),此時(shí)函數(shù)已經(jīng)被第三問執(zhí)行時(shí)修改,所以結(jié)果為。 JavaScript函數(shù)調(diào)用的經(jīng)典例題 很多初學(xué)JavaScript的人對(duì)函數(shù)的調(diào)用理解有些模糊的,話不多說,直接上題: function Foo() { getName = function...
摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽猓瑥膶?duì)語言感悟的角度闡述為什...
溫馨提示:作者的爬坑記錄,對(duì)你等大神完全沒有價(jià)值,別在我這浪費(fèi)生命 這一切,源于阮大神博文學(xué)習(xí)Javascript閉包(Closure)- 阮一峰中的一道思考題 //問題1: var name = The Window; var object = { name : My Object, getNameFunc : function(){ return function(){ ...
摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...
閱讀 2038·2023-04-25 14:50
閱讀 2917·2021-11-17 09:33
閱讀 2621·2019-08-30 13:07
閱讀 2847·2019-08-29 16:57
閱讀 914·2019-08-29 15:26
閱讀 3556·2019-08-29 13:08
閱讀 2001·2019-08-29 12:32
閱讀 3394·2019-08-26 13:57