介紹
JavaScript中有一個(gè)被稱為作用域(Scope)的特性灸芳。雖然對(duì)于許多新手開發(fā)者來(lái)說(shuō)珠移,作用域的概念并不是很容易理解倔丈,我會(huì)盡我所能用最簡(jiǎn)單的方式來(lái)解釋作用域灰嫉。理解作用域?qū)⑹鼓愕拇a脫穎而出郊酒,減少錯(cuò)誤遇绞,并幫助您使用它強(qiáng)大的設(shè)計(jì)模式键袱。
什么是作用域(Scope)?
作用域是在運(yùn)行時(shí)代碼中的某些特定部分中變量摹闽,函數(shù)和對(duì)象的可訪問(wèn)性蹄咖。換句話說(shuō),作用域決定了代碼區(qū)塊中變量和其他資源的可見性付鹿。
為什么說(shuō)作用域是最小訪問(wèn)原則澜汤?
那么,為什么要限制變量的可見性呢倘屹,為什么你的變量不是在代碼的任何地方都可用呢银亲?一個(gè)優(yōu)點(diǎn)是作用域?yàn)槟拇a提供了一定程度的安全性。計(jì)算機(jī)安全的一個(gè)常見原則是用戶應(yīng)該一次只能訪問(wèn)他們需要的東西纽匙。
想象一下計(jì)算機(jī)管理員务蝠。由于他們對(duì)公司的系統(tǒng)有很多控制權(quán)限,因此向他們授予超級(jí)管理員權(quán)限就好了烛缔。他們都可以完全訪問(wèn)系統(tǒng)馏段,一切工作順利。但突然發(fā)生了一些壞事践瓷,你的系統(tǒng)感染了惡意病毒≡合玻現(xiàn)在你不知道誰(shuí)犯的錯(cuò)誤?你意識(shí)到應(yīng)該授予普通用戶權(quán)限晕翠,并且只在需要時(shí)授予超級(jí)訪問(wèn)權(quán)限喷舀。這將幫助您跟蹤更改,并記錄誰(shuí)擁有什么帳戶淋肾。這被稱為最小訪問(wèn)原則硫麻。看起來(lái)很直觀樊卓?這個(gè)原則也適用于編程語(yǔ)言設(shè)計(jì)拿愧,在大多數(shù)編程語(yǔ)言中被稱為作用域,包括我們接下來(lái)要研究的 JavaScript 碌尔。
當(dāng)你繼續(xù)在你的編程旅程浇辜,您將意識(shí)到,您的代碼的作用域有助于提高效率唾戚,幫助跟蹤錯(cuò)誤并修復(fù)它們柳洋。作用域還解決了命名問(wèn)題,在不同作用域中變量名稱可以相同叹坦。記住不要將作用域與上下文混淆膳灶。它們的特性不同。
JavaScript中的作用域
在JavaScript中有兩種類型的作用域:
全局作用域
局部作用域(也叫本地作用域)
定義在函數(shù)內(nèi)部的變量具有局部作用域,而定義在函數(shù)外部的變量具有全局范圍內(nèi)轧钓。每個(gè)函數(shù)在被調(diào)用時(shí)都會(huì)創(chuàng)建一個(gè)新的作用域序厉。
全局作用域
當(dāng)您開始在文檔中編寫JavaScript時(shí),您已經(jīng)在全局作用域中了毕箍。全局作用域貫穿整個(gè)javascript文檔弛房。如果變量在函數(shù)之外定義,則變量處于全局作用域內(nèi)而柑。
JavaScript代碼:
// 默認(rèn)全局作用域
varname='Hammad';
在全局作用域內(nèi)的變量可以在任何其他作用域內(nèi)訪問(wèn)和修改文捶。
JavaScript代碼:
varname='Hammad';
console.log(name);// logs 'Hammad'
functionlogName(){
console.log(name);// 'name' 可以在這里和其他任何地方被訪問(wèn)
}
logName();// logs 'Hammad'
局部作用域
函數(shù)內(nèi)定義的變量在局部(本地)作用域中。而且個(gè)函數(shù)被調(diào)用時(shí)都具有不同的作用域媒咳。這意味著具有相同名稱的變量可以在不同的函數(shù)中使用粹排。這是因?yàn)檫@些變量被綁定到它們各自具有不同作用域的相應(yīng)函數(shù),并且在其他函數(shù)中不可訪問(wèn)涩澡。
JavaScript代碼:
// Global Scope
functionsomeFunction(){
// Local Scope #1
functionsomeOtherFunction(){
// Local Scope #2
}
}
// Global Scope
functionanotherFunction(){
// Local Scope #3
}
// Global Scope
塊語(yǔ)句
塊語(yǔ)句顽耳,如if和switch條件語(yǔ)句或for和while循環(huán)語(yǔ)句,不像函數(shù)妙同,它們不會(huì)創(chuàng)建一個(gè)新的作用域射富。在塊語(yǔ)句中定義的變量將保留在它們已經(jīng)存在的作用域中。
JavaScript代碼:
if(true){
// 'if' 條件語(yǔ)句塊不會(huì)創(chuàng)建一個(gè)新的作用域
varname='Hammad';// name 依然在全局作用域中
}
console.log(name);// logs 'Hammad'
ECMAScript 6 引入了let和const關(guān)鍵字粥帚∫群模可以使用這些關(guān)鍵字來(lái)代替var關(guān)鍵字。
JavaScript代碼:
varname='Hammad';
let likes='Coding';
constskills='Javascript and PHP';
與var關(guān)鍵字相反芒涡,let和const關(guān)鍵字支持在局部(本地)作用域的塊語(yǔ)句中聲明柴灯。
JavaScript代碼:
if(true){
// 'if' 條件語(yǔ)句塊不會(huì)創(chuàng)建一個(gè)新的作用域
// name 在全局作用域中,因?yàn)橥ㄟ^(guò) 'var' 關(guān)鍵字定義
varname='Hammad';
// likes 在局部(本地)作用域中费尽,因?yàn)橥ㄟ^(guò) 'let' 關(guān)鍵字定義
let likes='Coding';
// skills 在局部(本地)作用域中赠群,因?yàn)橥ㄟ^(guò) 'const' 關(guān)鍵字定義
constskills='JavaScript and PHP';
}
console.log(name);// logs 'Hammad'
console.log(likes);// Uncaught ReferenceError: likes is not defined
console.log(skills);// Uncaught ReferenceError: skills is not defined
只要您的應(yīng)用程序生活,全球作用域就會(huì)生存依啰。 只要您的函數(shù)被調(diào)用并執(zhí)行,局部(本地)作用域就會(huì)存在店枣。
上下文
許多開發(fā)人員經(jīng)乘倬混淆 作用域(scope) 和 上下文(context),很多誤解為它們是相同的概念鸯两。但事實(shí)并非如此闷旧。作用域(scope)我們上面已經(jīng)討論過(guò)了,而上下文(context)是用來(lái)指定代碼某些特定部分中this的值钧唐。作用域(scope) 是指變量的可訪問(wèn)性忙灼,上下文(context)是指this在同一作用域內(nèi)的值。我們也可以使用函數(shù)方法來(lái)改變上下文,將在稍后討論该园。 在全局作用域(scope)中上下文中始終是Window對(duì)象酸舍。(愚人碼頭注:取決于JavaScript 的宿主換環(huán)境,在瀏覽器中在全局作用域(scope)中上下文中始終是Window對(duì)象里初。在Node.js中在全局作用域(scope)中上下文中始終是Global對(duì)象)
JavaScript代碼:
// logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
console.log(this);
functionlogFunction(){
console.log(this);
}
// logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
// 因?yàn)?logFunction() 不是一個(gè)對(duì)象的屬性
logFunction();
如果作用域在對(duì)象的方法中啃勉,則上下文將是該方法所屬的對(duì)象。
ES6代碼:
classUser{
logName(){
console.log(this);
}
}
(newUser).logName();// logs User {}
(new User).logName() 是一種將對(duì)象存儲(chǔ)在變量中然后調(diào)用logName函數(shù)的簡(jiǎn)單方法双妨。在這里淮阐,您不需要?jiǎng)?chuàng)建一個(gè)新的變量。
您會(huì)注意到刁品,如果您使用new關(guān)鍵字調(diào)用函數(shù)泣特,則上下文的值會(huì)有所不同。然后將上下文設(shè)置為被調(diào)用函數(shù)的實(shí)例挑随±磁考慮上面的示例剔桨,通過(guò)new關(guān)鍵字調(diào)用的函數(shù)。
JavaScript代碼:
functionlogFunction(){
console.log(this);
}
newlogFunction();// logs logFunction {}
當(dāng)在嚴(yán)格模式(Strict Mode)中調(diào)用函數(shù)時(shí),上下文將默認(rèn)為undefined郭变。
執(zhí)行期上下文(Execution Context)
愚人碼頭注:這部分解釋建議先查看這篇文章,更加通俗易懂铜邮,http://www.css88.com/archives/7262
上面我們了解了作用域和上下文萨蚕,為了消除混亂,特別需要注意的是担猛,執(zhí)行期上下文中的上下文這個(gè)詞語(yǔ)是指作用域而不是上下文幕垦。這是一個(gè)奇怪的命名約定,但由于JavaScipt規(guī)范傅联,我們必須鏈接他們這間的聯(lián)系先改。
JavaScript是一種單線程語(yǔ)言,因此它一次只能執(zhí)行一個(gè)任務(wù)蒸走。其余的任務(wù)在執(zhí)行期上下文中排隊(duì)仇奶。正如我剛才所說(shuō),當(dāng) JavaScript 解釋器開始執(zhí)行代碼時(shí)比驻,上下文(作用域)默認(rèn)設(shè)置為全局该溯。這個(gè)全局上下文附加到執(zhí)行期上下文中,實(shí)際上是啟動(dòng)執(zhí)行期上下文的第一個(gè)上下文别惦。
之后狈茉,每個(gè)函數(shù)調(diào)用(啟用)將其上下文附加到執(zhí)行期上下文中。當(dāng)另一個(gè)函數(shù)在該函數(shù)或其他地方被調(diào)用時(shí)掸掸,會(huì)發(fā)生同樣的事情氯庆。
每個(gè)函數(shù)都會(huì)創(chuàng)建自己的執(zhí)行期上下文蹭秋。
一旦瀏覽器完成了該上下文中的代碼,那么該上下文將從執(zhí)行期上下文中銷毀堤撵,并且執(zhí)行期上下文中的當(dāng)前上下文的狀態(tài)將被傳送到父級(jí)上下文中仁讨。 瀏覽器總是執(zhí)行堆棧頂部的執(zhí)行期上下文(這實(shí)際上是代碼中最深層次的作用域)。
無(wú)論有多少個(gè)函數(shù)上下文粒督,但是全局上下文只有一個(gè)陪竿。
執(zhí)行期上下文有創(chuàng)建和代碼執(zhí)行的兩個(gè)階段。
創(chuàng)建階段
第一階段是創(chuàng)建階段屠橄,當(dāng)一個(gè)函數(shù)被調(diào)用但是其代碼還沒有被執(zhí)行的時(shí)族跛。 在創(chuàng)建階段主要做的三件事情是:
創(chuàng)建變量(激活)對(duì)象
創(chuàng)建作用域鏈
設(shè)置上下文(context)的值( `this` )
變量對(duì)象
變量對(duì)象,也稱為激活對(duì)象锐墙,包含在執(zhí)行期上下文中定義的所有變量礁哄,函數(shù)和其他聲明。當(dāng)調(diào)用函數(shù)時(shí)溪北,解析器掃描它所有的資源桐绒,包括函數(shù)參數(shù),變量和其他聲明之拨。包裝成一個(gè)單一的對(duì)象茉继,即變量對(duì)象。
JavaScript代碼:
'variableObject':{
// 包含函數(shù)參數(shù)蚀乔,內(nèi)部變量和函數(shù)聲明
}
作用域鏈
在執(zhí)行期上下文的創(chuàng)建階段烁竭,作用域鏈?zhǔn)窃谧兞繉?duì)象之后創(chuàng)建的。作用域鏈本身包含變量對(duì)象吉挣。作用域鏈用于解析變量派撕。當(dāng)被要求解析變量時(shí),JavaScript 始終從代碼嵌套的最內(nèi)層開始睬魂,如果最內(nèi)層沒有找到變量终吼,就會(huì)跳轉(zhuǎn)到上一層父作用域中查找,直到找到該變量或其他任何資源為止氯哮。作用域鏈可以簡(jiǎn)單地定義為包含其自身執(zhí)行上下文的變量對(duì)象的對(duì)象际跪,以及其父級(jí)對(duì)象的所有其他執(zhí)行期上下文,一個(gè)具有很多其他對(duì)象的對(duì)象喉钢。
JavaScript代碼:
'scopeChain':{
// 包含自己的變量對(duì)象和父級(jí)執(zhí)行上下文的其他變量對(duì)象
}
執(zhí)行期上下文對(duì)象
執(zhí)行期上下文可以表示為一個(gè)抽象對(duì)象姆打,如下所示:
JavaScript代碼:
executionContextObject={
'scopeChain':{},// 包含自己的變量對(duì)象和父級(jí)執(zhí)行上下文的其他變量對(duì)象
'variableObject':{},// 包含函數(shù)參數(shù),內(nèi)部變量和函數(shù)聲明
'this':valueOfThis
}
代碼執(zhí)行階段
在執(zhí)行期上下文的第二階段出牧,即代碼執(zhí)行階段穴肘,分配其他值并最終執(zhí)行代碼歇盼。
詞法作用域
詞法作用域意味著在一組嵌套的函數(shù)中舔痕,內(nèi)部函數(shù)可以訪問(wèn)其父級(jí)作用域中的變量和其他資源。這意味著子函數(shù)在詞法作用域上綁定到他們父級(jí)的執(zhí)行期上下文。詞法作用域有時(shí)也被稱為靜態(tài)作用域伯复。
JavaScript代碼:
functiongrandfather(){
varname='Hammad';
// likes 在這里不可以被訪問(wèn)
functionparent(){
// name 在這里可以被訪問(wèn)
// likes 在這里不可以被訪問(wèn)
functionchild(){
// 作用域鏈最深層
// name 在這里也可以被訪問(wèn)
varlikes='Coding';
}
}
}
你會(huì)注意到詞法作用域向內(nèi)傳遞的慨代,意味著name可以通過(guò)它的子級(jí)期執(zhí)行期上下文訪問(wèn)。但是啸如,但是它不能向其父對(duì)象反向傳遞侍匙,意味著變量likes不能被其父對(duì)象訪問(wèn)。這也告訴我們叮雳,在不同執(zhí)行上下文中具有相同名稱的變量從執(zhí)行堆棧的頂部到底部獲得優(yōu)先級(jí)想暗。在最內(nèi)層函數(shù)(執(zhí)行堆棧的最上層上下文)中,具有類似于另一變量的名稱的變量將具有較高優(yōu)先級(jí)帘不。
閉包(?Closures)
愚人碼頭注:這部分解釋建議先查看這篇文章说莫,更加通俗易懂,http://www.css88.com/archives/7262
閉包的概念與我們?cè)谏厦嬷v的詞法作用域密切相關(guān)寞焙。 當(dāng)內(nèi)部函數(shù)嘗試訪問(wèn)其外部函數(shù)的作用域鏈储狭,即在直接詞法作用域之外的變量時(shí),會(huì)創(chuàng)建一個(gè)閉包捣郊。 閉包包含自己的作用域鏈辽狈,父級(jí)的作用域鏈和全局作用域。
閉包不僅可以訪問(wèn)其外部函數(shù)中定義的變量呛牲,還可以訪問(wèn)外部函數(shù)的參數(shù)刮萌。
即使函數(shù)返回后,閉包也可以訪問(wèn)其外部函數(shù)的變量侈净。這允許返回的函數(shù)保持對(duì)外部函數(shù)所有資源的訪問(wèn)尊勿。
當(dāng)從函數(shù)返回內(nèi)部函數(shù)時(shí),當(dāng)您嘗試調(diào)用外部函數(shù)時(shí)畜侦,不會(huì)調(diào)用返回的函數(shù)元扔。您必須首先將外部函數(shù)的調(diào)用保存在單獨(dú)的變量中,然后將該變量調(diào)用為函數(shù)旋膳∨煊铮考慮這個(gè)例子:
JavaScript代碼:
functiongreet(){
name='Hammad';
returnfunction(){
console.log('Hi '+name);
}
}
greet();// 什么都沒發(fā)生,沒有錯(cuò)誤
// 從 greet() 中返回的函數(shù)保存到 greetLetter 變量中
greetLetter=greet();
// 調(diào)用? greetLetter 相當(dāng)于調(diào)用從 greet() 函數(shù)中返回的函數(shù)
greetLetter();// logs 'Hi Hammad'
這里要注意的是验懊,greetLetter函數(shù)即使在返回后也可以訪問(wèn)greet函數(shù)的name變量擅羞。 有一種方法不需要分配一個(gè)變量來(lái)訪問(wèn)greet函數(shù)返回的函數(shù),即通過(guò)使用兩次括號(hào)()义图,即()()來(lái)調(diào)用减俏,就是這樣:
JavaScript代碼:
functiongreet(){
name='Hammad';
returnfunction(){
console.log('Hi '+name);
}
}
greet()();// logs 'Hi Hammad'
公共作用域和私有作用域
在許多其他編程語(yǔ)言中,您可以使用公共碱工,私有和受保護(hù)的作用域來(lái)設(shè)置類的屬性和方法的可見性娃承∽喾颍考慮使用PHP語(yǔ)言的這個(gè)例子:
PHP代碼:
// Public Scope
public$property;
publicfunctionmethod(){
// ...
}
// Private Sccpe
private$property;
privatefunctionmethod(){
// ...
}
// Protected Scope
protected$property;
protectedfunctionmethod(){
// ...
}
來(lái)自公共(全局)作用域的封裝函數(shù)使他們免受脆弱的攻擊。但是在JavaScript中历筝,沒有公共或私有作用域酗昼。幸好,我們可以使用閉包來(lái)模擬此功能梳猪。為了保持一切與全局分離麻削,我們必須首先將我們的函數(shù)封裝在如下所示的函數(shù)中:
JavaScript代碼:
(function(){
// 私有作用域 private scope
})();
函數(shù)末尾的括號(hào)會(huì)告知解析器在沒有調(diào)用的情況下一旦讀取完成就立即執(zhí)行它。(愚人碼頭注:這其實(shí)叫立即執(zhí)行函數(shù)表達(dá)式)我們可以在其中添加函數(shù)和變量春弥,它們將不能在外部訪問(wèn)呛哟。但是,如果我們想在外部訪問(wèn)它們匿沛,也就是說(shuō)我們希望其中一些公開的竖共,另一些是私有的?我們可以使用一種稱為 模塊模式 的閉包類型俺祠,它允許我們使用對(duì)象中公共和私有的作用域來(lái)對(duì)我們的函數(shù)進(jìn)行調(diào)整公给。
模塊模式
模塊模式類似這樣:
JavaScript代碼:
varModule=(function(){
functionprivateMethod(){
// do something
}
return{
publicMethod:function(){
// can call privateMethod();
}
};
})();
Module中的return語(yǔ)句包含了我們公開的函數(shù)。私有函數(shù)只是那些沒有返回的函數(shù)蜘渣。沒有返回的函數(shù)不可以在Module命名空間之外訪問(wèn)淌铐。但是公開函數(shù)可以訪問(wèn)私有函數(shù),這使它們對(duì)于助手函數(shù)蔫缸,AJAX調(diào)用和其他事情很方便腿准。
JavaScript代碼:
Module.publicMethod();// 可以正常工作
Module.privateMethod();// Uncaught ReferenceError: privateMethod is not defined
私有函數(shù)一個(gè)慣例是用下劃線開始,并返回一個(gè)包含我們公共函數(shù)的匿名對(duì)象拾碌。這使得它們很容易在長(zhǎng)對(duì)象中管理吐葱。它看起來(lái)是這樣子的:
JavaScript代碼:
varModule=(function(){
function_privateMethod(){
// do something
}
functionpublicMethod(){
// do something
}
return{
publicMethod:publicMethod,
}
})();
立即執(zhí)行函數(shù)表達(dá)式(IIFE)
另一種類型的閉包是立即執(zhí)行函數(shù)表達(dá)式(IIFE)。這是一個(gè)在window上下文中調(diào)用的自動(dòng)調(diào)用的匿名函數(shù)校翔,這意味著this的值為window弟跑。暴露一個(gè)單一的全局接口來(lái)進(jìn)行交互。他是這樣的:
JavaScript代碼:
(function(window){
// do anything
})(this);
使用 .call(), .apply() 和 .bind() 改變上下文
.call()和.apply()函數(shù)用于在調(diào)用函數(shù)時(shí)改變上下文防症。這給了你令人難以置信的編程能力(和一些終極權(quán)限來(lái)駕馭代碼)孟辑。
要使用call或apply函數(shù),您只需要在函數(shù)上調(diào)用它蔫敲,而不是使用一對(duì)括號(hào)調(diào)用函數(shù)饲嗽,并將新的上下文作為第一個(gè)參數(shù)傳遞。
函數(shù)自己的參數(shù)可以在上下文之后傳遞奈嘿。(愚人碼頭注:call或apply用另一個(gè)對(duì)象來(lái)調(diào)用一個(gè)方法貌虾,將一個(gè)函數(shù)上下文從初始的上下文改變?yōu)橹付ǖ男聦?duì)象。簡(jiǎn)單的說(shuō)就是改變函數(shù)執(zhí)行的上下文裙犹。)
JavaScript代碼:
functionhello(){
// do something...
}
hello();// 通常的調(diào)用方式
hello.call(context);// 在這里你可以傳遞上下文(this 值)作為第一個(gè)參數(shù)
hello.apply(context);// 在這里你可以傳遞上下文(this 值)作為第一個(gè)參數(shù)
.call()和.apply()之間的區(qū)別在于尽狠,在.call()中榴鼎,其余參數(shù)作為以逗號(hào)分隔的列表,而.apply()則允許您在數(shù)組中傳遞參數(shù)晚唇。
JavaScript代碼:
functionintroduce(name,interest){
console.log('Hi! I\'m '+name+' and I like '+interest+'.');
console.log('The value of this is '+this+'.')
}
introduce('Hammad','Coding');// 通常的調(diào)用方式
introduce.call(window,'Batman','to save Gotham');// 在上下文之后逐個(gè)傳遞參數(shù)
introduce.apply('Hi',['Bruce Wayne','businesses']);// 在上下文之后傳遞數(shù)組中的參數(shù)
// 輸出:
// Hi! I'm Hammad and I like Coding.
// The value of this is [object Window].
// Hi! I'm Batman and I like to save Gotham.
// The value of this is [object Window].
// Hi! I'm Bruce Wayne and I like businesses.
// The value of this is Hi.
.call()的性能要比.apply()稍快。
以下示例將文檔中的項(xiàng)目列表逐個(gè)記錄到控制臺(tái)盗似。
HTML 代碼:
Things to learn
Things to Learn to Rule the World
Learn PHP
Learn Laravel
Learn JavaScript
Learn VueJS
Learn CLI
Learn Git
Learn Astral Projection
// 在listItems中保存頁(yè)面上所有列表項(xiàng)的NodeList
varlistItems=document.querySelectorAll('ul li');
// 循環(huán)遍歷listItems NodeList中的每個(gè)節(jié)點(diǎn)哩陕,并記錄其內(nèi)容
for(vari=0;i
(function(){
console.log(this.innerHTML);
}).call(listItems[i]);
}
// Output logs:
// Learn PHP
// Learn Laravel
// Learn JavaScript
// Learn VueJS
// Learn CLI
// Learn Git
// Learn Astral Projection
HTML僅包含無(wú)序的項(xiàng)目列表。然后 JavaScript 從DOM中選擇所有這些項(xiàng)目赫舒。列表循環(huán)悍及,直到列表中的項(xiàng)目結(jié)束。在循環(huán)中接癌,我們將列表項(xiàng)的內(nèi)容記錄到控制臺(tái)心赶。
該日志語(yǔ)句包裹在一個(gè)函數(shù)中,該call函數(shù)包含在調(diào)用函數(shù)中的括號(hào)中缺猛。將相應(yīng)的列表項(xiàng)傳遞給調(diào)用函數(shù)缨叫,以便控制臺(tái)語(yǔ)句中的this關(guān)鍵字記錄正確對(duì)象的 innerHTML 。
對(duì)象可以有方法荔燎,同樣的函數(shù)對(duì)象也可以有方法耻姥。 事實(shí)上,JavaScript函數(shù)附帶了四種內(nèi)置方法:
Function.prototype.apply()
Function.prototype.bind() ( ECMAScript 5 (ES5) 中引進(jìn))
Function.prototype.call()
Function.prototype.toString()
Function.prototype.toString() 返回函數(shù)源代碼的字符串表示形式有咨。
到目前為止琐簇,我們討論過(guò).call(),.apply()和toString()座享。與.call()和.apply()不同婉商,.bind()本身不調(diào)用該函數(shù),它只能用于在調(diào)用函數(shù)之前綁定上下文和其他參數(shù)的值渣叛。在上面的一個(gè)例子中使用.bind():
JavaScript代碼:
(functionintroduce(name,interest){
console.log('Hi! I\'m '+name+' and I like '+interest+'.');
console.log('The value of this is '+this+'.')
}).bind(window,'Hammad','Cosmology')();
// logs:
// Hi! I'm Hammad and I like Cosmology.
// The value of this is [object Window].
.bind()就像.call()函數(shù)一樣丈秩,它允許你傳遞其余的參數(shù),用逗號(hào)分隔淳衙,而不是像apply癣籽,在數(shù)組中傳遞參數(shù)。
結(jié)論
這些概念是 JavaScript 的根本滤祖,對(duì)于了解高級(jí)語(yǔ)法很重要筷狼。我希望你能更好地了解JavaScript作用域和他相關(guān)的事情。如果沒用弄明白這些問(wèn)題匠童,歡迎在下面的評(píng)論中提問(wèn)埂材。
原文地址:https://scotch.io/tutorials/understanding-scope-in-javascript