摘要:有關(guān)函數(shù)柯里化的詳解,請(qǐng)回閱前端進(jìn)擊的巨人五學(xué)會(huì)函數(shù)柯里化。構(gòu)造函數(shù)中的通過操作符可以實(shí)現(xiàn)對(duì)函數(shù)的構(gòu)造調(diào)用。在了解構(gòu)造函數(shù)中的前,有必要先了解下實(shí)例化對(duì)象的過程。
常見this的誤解
指向函數(shù)自身(源于this英文意思的誤解)
指向函數(shù)的詞法作用域(部分情況)
this的應(yīng)用環(huán)境 1. 全局環(huán)境無論是否在嚴(yán)格模式下,全局執(zhí)行環(huán)境中(任何函數(shù)體外部)this都指向全局對(duì)象
var name = "以樂之名"; this.name; // 以樂之名
函數(shù)內(nèi)部,this的值取決于函數(shù)被調(diào)用的方式(被誰調(diào)用)
var name = "無名氏"; function getName() { console.log(this.name); } getName(); // 無名氏 調(diào)用者是全局對(duì)象 var myInfo = { name: "以樂之名", getName: getName }; myInfo.getName(); // 以樂之名 調(diào)用者是myInfo對(duì)象this的正解
"this的指向是在運(yùn)行時(shí)進(jìn)行綁定的,而不是代碼書寫(函數(shù)聲明)時(shí)確定!!!"
"看誰用",this的指向取決于調(diào)用者,這也是很多文章提到過的觀點(diǎn)。"誰調(diào)用,this指向誰",只是這句話稍有偏頗,某些情況不見得都適用。
生活栗子:你的錢并不一定是你的錢,只有當(dāng)你使用消費(fèi)了才是你的錢 。
("看誰用"),借出去的錢就不是你的了。。。
回到正文,我們先通過棧,來理解什么是調(diào)用位置?
JavaScript中函數(shù)的調(diào)用是以棧的方式來存儲(chǔ),棧頂是正在運(yùn)行的函數(shù),函數(shù)調(diào)用時(shí)入棧,執(zhí)行完成后出棧。
function foo() { // 此時(shí)的棧:全局 -> foo,調(diào)用位置在foo bar(); } function bar() { // 此時(shí)的棧:全局 -> foo -> bar,調(diào)用位置在bar baz(); } function baz() { // 此時(shí)的棧:全局 -> foo -> bar -> baz,調(diào)用位置在baz // ... } foo();
代碼中雖然函數(shù)存在多層嵌套使用,但處于棧頂?shù)闹挥姓趫?zhí)行的函數(shù),也即調(diào)用者只有頂層的那一個(gè)(或最后一個(gè)),理清調(diào)用位置(調(diào)用者)有助于我們理解this。
this的綁定規(guī)則默認(rèn)綁定(函數(shù)多帶帶調(diào)用)
隱式綁定(作為對(duì)象的屬性方法調(diào)用,帶有執(zhí)行上下文)
顯示綁定(call/apply/bind)
new綁定(new創(chuàng)建實(shí)例)
箭頭函數(shù)綁定(ES6新增,基于詞法作用域)
默認(rèn)綁定下(函數(shù)多帶帶調(diào)用)區(qū)分嚴(yán)格模式非嚴(yán)格模式,this會(huì)指向全局對(duì)象(瀏覽器全局對(duì)象是window,NodeJS全局對(duì)象是global);
嚴(yán)格模式,this指向undefined
// 非嚴(yán)格模式 function getName() { console.log(this.name); // this指向全局對(duì)象 } getName(); // "",并不會(huì)報(bào)錯(cuò),如果外部有全局變量name,則會(huì)輸出對(duì)應(yīng)值 // 嚴(yán)格模式 function getName() { "use strict" console.log(this.name); // this指向undefined } getName(); // TypeError: Cannot read property "name" of undefined
TIPS: 嚴(yán)格模式中,對(duì)函數(shù)中this的影響,只在函數(shù)內(nèi)聲明了嚴(yán)格模式才會(huì)存在,如果是調(diào)用時(shí)聲明嚴(yán)格模式則不會(huì)影響。
function getName() { console.log(this.name); } // 調(diào)用時(shí)聲明嚴(yán)格模式 "use strict"; getName(); // ""隱式綁定
隱式綁定中,函數(shù)一般作為對(duì)象的屬性調(diào)用,帶有調(diào)用者的執(zhí)行上下文。因此this值取決于調(diào)用者的上下文環(huán)境。如果存在多層級(jí)屬性引用,只有對(duì)象屬性引用鏈中最頂層(最后一層)會(huì)影響調(diào)用位置,而this的值取決于調(diào)用位置。文章開頭以棧來理解調(diào)用者的例子。
function getName() { return this.name; } var myInfo = { name: "以樂之名", getName: getName }; var leader = { name: "大神組長(zhǎng)" man: myInfo }; leader.man.getName(); // "以樂之名" // man 指向 myInfo,最頂層(最后一層)對(duì)象為 myInfoapply/call的區(qū)別
apply/call方法兩者類似,都可以顯示綁定this,兩者的區(qū)別是參數(shù)傳遞的方式不同。apply/call第一個(gè)參數(shù)都為要指定this的對(duì)象,不同的是apply第二個(gè)參數(shù)接受的是一個(gè)參數(shù)數(shù)組,而call從第二個(gè)參數(shù)開始接受的是參數(shù)列表。
apply語法:func.apply(thisArg, [argsArray])call語法:func.call(thisArg, arg1, arg2, ...)
var numbers = [5, 6, 2, 3, 7]; // 求numbers的最大值 // apply var max = Math.max.apply(null, numbers); // call var max = Math.max.call(null, ...numbers); // ...展開運(yùn)算符
TIPS: 如果thisArg為原始值(數(shù)字,字符串,布爾值),this會(huì)指向該原始值的自動(dòng)包裝對(duì)象,如Number, String, Boolean等
func.apply(1); // func中的this -> Number對(duì)象;bind的特別(柯里化的應(yīng)用)
bind是ES5新增的方法,跟apply/call功能一樣,可以顯示綁定this。
bind語法:function.bind(thisArg[, arg1[, arg2[, ...]]])bind()方法創(chuàng)建一個(gè)新的函數(shù),在調(diào)用時(shí)設(shè)置this關(guān)鍵字為提供的值,并在調(diào)用新函數(shù)時(shí),將給定參數(shù)列表作為原函數(shù)的參數(shù)序列的前若干項(xiàng)。
-- 《Function.prototype.bind() | MDN》
"bind與apply/call的區(qū)別:apply/call傳入this并立即執(zhí)行函數(shù),而bind傳入this則返回一個(gè)函數(shù),并不會(huì)立即執(zhí)行,只有調(diào)用返回的函數(shù)才會(huì)執(zhí)行原始函數(shù)"。
bind方法是函數(shù)柯里化的一種應(yīng)用,看過上篇《前端進(jìn)擊的巨人(五):學(xué)會(huì)函數(shù)柯里化(curry) 》的小伙伴,應(yīng)該還記得"函數(shù)柯里化的特點(diǎn):延遲執(zhí)行,部分傳參,返回一個(gè)可處理剩余參數(shù)的函數(shù)"。
bind相較apply/call的優(yōu)點(diǎn),可以通過部分傳參提前對(duì)this進(jìn)行一次"永久綁定",也就是說this只需綁定一次,省卻每次執(zhí)行都要進(jìn)行this綁定的操作。
function getName() { return this.name; } var myInfo = { name: "以樂之名", job: "前端工程師" }; var getName = getName.bind(myInfo); getName(); // "以樂之名"; getName(); // "以樂之名"; // 一次性綁定,之后調(diào)用無需再修改this
TIPS: 函數(shù)柯里化可以用于參數(shù)預(yù)設(shè),像一次性操作(判斷/綁定)等。
有關(guān)函數(shù)柯里化的詳解,請(qǐng)回閱:《前端進(jìn)擊的巨人(五):學(xué)會(huì)函數(shù)柯里化(curry) 》。
構(gòu)造函數(shù)中的this通過new操作符可以實(shí)現(xiàn)對(duì)函數(shù)的構(gòu)造調(diào)用。JavaScript中本身并沒有"構(gòu)造函數(shù)",一個(gè)函數(shù)如果沒有使用new操作符調(diào)用,那么它就是個(gè)普通函數(shù),new Func()實(shí)際上是對(duì)函數(shù)Func的"構(gòu)造調(diào)用"。
在了解構(gòu)造函數(shù)中的this前,有必要先了解下new實(shí)例化對(duì)象的過程。
new實(shí)例過程創(chuàng)建(構(gòu)造)一個(gè)全新的空對(duì)象
這個(gè)新對(duì)象會(huì)被執(zhí)行"原型"鏈接(新對(duì)象的__proto__會(huì)指向函數(shù)的prototype)
構(gòu)造函數(shù)的this會(huì)指向這個(gè)新對(duì)象,并對(duì)this屬性進(jìn)行賦值
如果函數(shù)沒有返回其他對(duì)象,則返回這個(gè)新對(duì)象(注意構(gòu)造函數(shù)的return,一般不會(huì)有return)
// 正常不帶return的構(gòu)造函數(shù) function People(name, sex) { this.name = name; this.sex = sex; } var man = new People("亞當(dāng)", "男"); var woman = new People("夏娃", "女"); // 實(shí)例化對(duì)象成功
// 構(gòu)造函數(shù)帶了return function People(name, sex) { return 1; // 返回的是Number對(duì)象 } function People(name, sex) { return "hello world"; // 返回的是String對(duì)象 } function People(name, sex) { return function() {} } function People(name, sex) { return {}; } // 以上并未正確實(shí)例化對(duì)象
構(gòu)造函數(shù)自定義return,會(huì)造成new無法完成正確的實(shí)例化操作。如果返回值為基本類型,則返回其包裝對(duì)象Number/String/Bollean。
TIPS: 原型鏈中的this指向其實(shí)例化的對(duì)象
People.prototype.say = function() { console.log(`我的名字:${this.name}`); }; var man = new People("亞當(dāng)", "男"); man.say(); // 我的名字:亞當(dāng)this綁定規(guī)則的優(yōu)先級(jí)
顯示綁定 / new綁定 > 隱式綁定 > 默認(rèn)綁定
TIPS: new無法跟apply/call同時(shí)使用
this判定步驟函數(shù)被new操作符使用(new綁定)? YES --> this綁定的是new創(chuàng)建的新對(duì)象
函數(shù)通過call/apply/bind(顯示綁定)? YES --> this綁定的是指定的對(duì)象
函數(shù)在某個(gè)上下文對(duì)象中調(diào)用(隱式綁定)? YES --> this綁定的是那個(gè)上下文對(duì)象
默認(rèn)綁定,嚴(yán)格模式指向undefined,否則指向全局對(duì)象
ES6的箭頭函數(shù)(詞法作用域的this機(jī)制,規(guī)則之外)箭頭函數(shù)的this機(jī)制不同于傳統(tǒng)的this機(jī)制,它采取的是另外一種機(jī)制,詞法作用域的this判定規(guī)則。
// 例子一 var name = "無名氏"; var myInfo = { name: "以樂之名", getName: () => { console.log(this.name); } }; var getName = myInfo.getName; window.getName(); // 無名氏 myInfo.getName(); // 無名氏 // myInfo是在全局環(huán)境定義的,因此根據(jù)詞法作用域,this指向全局對(duì)象 // 例子二 var name = "無名氏"; var myInfo = { name: "以樂之名", say: () => { setTimeout(() => { console.log(this.name); }) } }; myInfo.say(); // 無名氏 // 箭頭函數(shù)通過作用域鏈來逐層查找this,最終找到全局變量myInfo,this指向全局對(duì)象 // 例子三 var name = "無名氏"; var myInfo = { name: "以樂之名", say: function() { setTimeout(() => { console.log(this.name); }) } }; myInfo.say(); // 以樂之名 // 箭頭函數(shù)找到say: function(){},因此this的作用域來自myInfo
TIPS: setTimeout/setInterval/alert的調(diào)用者都是全局對(duì)象
"箭頭函數(shù)的this始終指向函數(shù)定義時(shí)的this,而非執(zhí)行(調(diào)用)時(shí)的this。箭頭函數(shù)中的this必須通過作用域鏈一層一層向外查找,來確定this指向。"
擴(kuò)展:箭頭函數(shù)的書寫規(guī)則// 函數(shù)表達(dá)式 const getName = (name) => { return "myName: " + name }; // 匿名函數(shù) setTimeout((name) => { console.log(name); }, 1000)
// 只有一個(gè)參數(shù) const getName = name => { return `myName: ${name}`; } // 無參數(shù) const getName = () => { return "myName: "以樂之名""; } // 多參數(shù) const getName = (firstName, lastName) => { return `myName: ${firstName} ${lastName}`; }
const getName = name => return `myName: ${name}`;
const getName = name => `myName: ${name}`;
參考文檔:
你不知道的JavaScript(上卷)
徹底理解js中this的指向,不必硬背。
this|MDN
本文首發(fā)Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創(chuàng),有不當(dāng)?shù)牡胤綒g迎指出。轉(zhuǎn)載請(qǐng)指明出處。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/108949.html
摘要:初始化隊(duì)列初始化一個(gè)存儲(chǔ)隊(duì)列中元素的數(shù)據(jù)結(jié)構(gòu),如果未傳入默認(rèn)賦值空數(shù)組,傳入需先校驗(yàn)類型是否正確。頭等艙和商務(wù)艙乘客的優(yōu)先級(jí)要高于經(jīng)濟(jì)艙乘客。在有些國(guó)家,老年人和孕婦或帶小孩的婦女登機(jī)時(shí)也享有高于其他乘客的優(yōu)先級(jí)。 有一天,當(dāng)回顧自己走過的路時(shí),你會(huì)發(fā)現(xiàn)這些奮斗不息的歲月,才是最美好的人生。——弗洛伊德 隊(duì)列,英文 First In First Out 簡(jiǎn)稱 FIFO,遵從先進(jìn)先出的原...
摘要:超融合的持續(xù)演進(jìn)與企業(yè)數(shù)字化轉(zhuǎn)型的步調(diào)是一致的,這也是超融合受到業(yè)界追捧的原因。對(duì)于超融合市場(chǎng)的每一個(gè)參與者來說,目前最重要的任務(wù)是如何快速有效地獲客。而這也正是超融合市場(chǎng)走向縱深所需的后勁兒,也是持續(xù)發(fā)展所需要的韌勁兒。超融合(HCI)市場(chǎng)可以一直火熱,但超融合應(yīng)用的落地最好理智而冷靜。最熱時(shí),據(jù)說中國(guó)市場(chǎng)有上百家超融合供應(yīng)商。隨著超融合應(yīng)用逐步落地,在市場(chǎng)和用戶需求的雙重考驗(yàn)下,有人離開...
摘要:當(dāng)用戶或搜索引擎向網(wǎng)站服務(wù)器發(fā)出瀏覽請(qǐng)求時(shí),服務(wù)器返回的數(shù)據(jù)流中頭信息中的狀態(tài)碼的一種,表示本網(wǎng)頁永久性轉(zhuǎn)移到另一個(gè)地址。通過在源代碼中添加日志輸出,我們也能清楚地看到的狀態(tài)碼。 Created 2019-4-5 22:24:33 by huqi Updated 2019-4-5 23:23:56 by huqi showImg(https://segmentfault.com/...
摘要:隆重請(qǐng)出主角防抖與節(jié)流。防抖與節(jié)流的異同相同都是防止某一時(shí)間段內(nèi),函數(shù)被頻繁調(diào)用執(zhí)行,通過時(shí)間頻率控制,減少回調(diào)函數(shù)執(zhí)行次數(shù),來實(shí)現(xiàn)相關(guān)性能優(yōu)化。參考文章分鐘理解的節(jié)流防抖及使用場(chǎng)景函數(shù)防抖和節(jié)流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇課題,或許早已是爛大街的解讀文章。不過春招系列面試下來,不少伙伴們還...
閱讀 2521·2023-04-26 02:57
閱讀 1403·2023-04-25 21:40
閱讀 2155·2021-11-24 09:39
閱讀 3557·2021-08-30 09:49
閱讀 760·2019-08-30 15:54
閱讀 1166·2019-08-30 15:52
閱讀 2069·2019-08-30 15:44
閱讀 1274·2019-08-28 18:27