下一篇:《你不知道的javascript》筆記_對(duì)象&原型
寫在前面上一篇博客我們知道詞法作用域是由變量書寫的位置決定的,那this又是在哪里確定的呢?如何能夠精準(zhǔn)的判斷this的指向?這篇博客會(huì)逐條闡述
書中有這樣幾句話:
this是在運(yùn)行時(shí)進(jìn)行綁定的,并不是在編寫時(shí)綁定,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件
this的綁定和函數(shù)聲明的位置沒有任何關(guān)系,只取決于函數(shù)的調(diào)用方式當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)活動(dòng)記錄(有時(shí)候也稱為執(zhí)行上下文)。這個(gè)記錄會(huì)包含函數(shù)在哪里被調(diào)用(調(diào)用棧)、函數(shù)的調(diào)用方法、傳入的參數(shù)等信息。this 就是記錄的其中一個(gè)屬性,會(huì)在函數(shù)執(zhí)行的過程中用到。
關(guān)于執(zhí)行上下文,可以參考《javascript高級(jí)程序設(shè)計(jì)》筆記:內(nèi)存與執(zhí)行環(huán)境
一、 綁定規(guī)則 1.1 默認(rèn)綁定最常用的函數(shù)調(diào)用類型——獨(dú)立函數(shù)調(diào)用,使用的即為默認(rèn)綁定規(guī)則,在非strict mode下,this指向全局對(duì)象
function foo1() { console.log(this.a); } var a = 10; foo1(); // 10 // 即使函數(shù)嵌套比較深 function foo2() { foo1(); } function foo3() { foo2(); } foo3();
當(dāng)然,我們實(shí)際使用中,難以判別的并不是直接型的默認(rèn)綁定模式,而是隱式綁定丟失型的默認(rèn)綁定(下面會(huì)著重說明)
1.2 隱式綁定【重點(diǎn)】調(diào)用的位置是否有上下文對(duì)象,或者說被某個(gè)對(duì)象擁有或包含
// 基本形式 function foo() { console.log(this.a); } var obj = { a: 10, foo }; obj.foo(); // 10
隱式綁定中的幾個(gè)雷區(qū):
1. 多個(gè)對(duì)象嵌套引用時(shí),只有最后一層在調(diào)用位置中起作用
function foo() { console.log(this.a); } var obj2 = { a: 42, foo }; var obj1 = { a: 10, obj2 }; obj1.obj2.foo(); // 42
2.【隱式丟失】當(dāng)調(diào)用函數(shù)被重新賦值為新變量,調(diào)用新變量時(shí)this指向會(huì)有不同
// 共用部分 function foo(){ console.log(this.a); } var obj = { a: 10, foo }; var a = "opps, global"; // 直接賦值 var bar = obj.foo; bar(); // "oops, global" // 回調(diào)間接賦值1 function doFoo(fn) { fn(); } doFoo(obj.foo); // "oops, global" 相當(dāng)于間接賦值 // 回調(diào)間接賦值2 setTimeout(obj.foo, 100); // "oops, global" 內(nèi)置的setTimeout也相當(dāng)于間接賦值
經(jīng)典綜合案例:
var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); arguments[0](); } }; obj.method(fn, 123);
分析:fn()為函數(shù)fn的引用,默認(rèn)綁定,指向全局;arguments[0]();相當(dāng)于下面的引用,數(shù)據(jù)隱式綁定,綁定對(duì)象為arguments,其屬性length值為參數(shù)數(shù)量2
arguments: { "0": function fn(){ console.log(this.length); } }
答案:10 2
1.3 顯式綁定call()/apply()/bind()能夠顯式修改this指向
通過上述方法調(diào)用的方式為顯示綁定,它們第一個(gè)參數(shù)是一個(gè)對(duì)象,在調(diào)用函數(shù)時(shí),綁定在this中。
關(guān)于三者的基本用法和說明在之前博客《javascript高級(jí)程序設(shè)計(jì)》函數(shù)調(diào)用模式 & this深度理解中已作說明,在此不做嘮述
兩點(diǎn)注意:
1. 通過顯式綁定的不能再修改它的this指向
function foo() { console.log(this.a); } var obj = { a: 2 }; var bar = function() { foo.call(obj); } bar(); // 2 setTimeout(bar, 200); // 2 bar.call(window); // 2
2. 將null/undefined作為第一個(gè)參數(shù)時(shí),調(diào)用會(huì)忽略這些值,采用默認(rèn)綁定規(guī)則
function foo() { console.log(this.a); } var a = 2; foo.call(null); // 21.4 new綁定
使用關(guān)鍵字new執(zhí)行函數(shù),當(dāng)函數(shù)無返回值或返回值非對(duì)象時(shí),this指向?yàn)閷?shí)例對(duì)象
new關(guān)鍵字執(zhí)行函數(shù)流程:
創(chuàng)建一個(gè)全新的對(duì)象
這個(gè)新對(duì)象會(huì)被執(zhí)行[[prototype]]連接
這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this上
如果函數(shù)沒有返回其他對(duì)象,所執(zhí)行函數(shù)會(huì)自動(dòng)返回這個(gè)新的對(duì)象
須知:構(gòu)造函數(shù)與普通函數(shù)無異,作為區(qū)分,我們一般講通過new調(diào)用的函數(shù)稱為構(gòu)造函數(shù),并大寫第一個(gè)單詞。所有函數(shù)均可由關(guān)鍵字new調(diào)用
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); // 2二、優(yōu)先級(jí)&判斷規(guī)則 2.1 優(yōu)先級(jí)
new綁定 --> 顯式綁定 --> 隱式綁定 --> 默認(rèn)綁定
2.2. 判斷規(guī)則【重點(diǎn)】【new綁定】函數(shù)是否在new中調(diào)用?如果是,this綁定的是新創(chuàng)建的對(duì)象
【顯式綁定】函數(shù)是否在call/aplly/bind中調(diào)用?如果是,this綁定的是指定對(duì)象
【隱式綁定】函數(shù)是否在某個(gè)上下文中調(diào)用?如果是,this綁定到那個(gè)上下文對(duì)象
【默認(rèn)綁定】如果都不是,this綁定嚴(yán)格模式下為undefined,非嚴(yán)格模式下為全局對(duì)象
三、箭頭函數(shù)中的thisES6中箭頭函數(shù)不使用上面this的四種標(biāo)準(zhǔn)規(guī)格,而是根據(jù)外層(函數(shù)或者全局)作用域來決定this指向
下面是一個(gè)普通函數(shù)和箭頭函數(shù)的對(duì)比:
function foo1() { setTimeout(() => { console.log(this.a) }, 100) } function foo2() { setTimeout(function() { console.log(this.a) }, 100) } var a = 10; var obj = { a: 2 }; foo1.call(obj); // 2 箭頭函數(shù)this指向外層(obj) foo2.call(obj); // 10 隱式丟失,默認(rèn)綁定
【利用閉包】理解箭頭函數(shù)中的this:
// 上例中的箭頭函數(shù)相當(dāng)于 function foo1() { var self = this; setTimeout(function() { console.log(self.a) }, 100) }
上一篇:《你不知道的javascript》筆記_作用域與閉包
下一篇:《你不知道的javascript》筆記_對(duì)象&原型
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100381.html
摘要:上一篇你不知道的筆記寫在前面這是年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響年是向上的一年在新的城市穩(wěn)定連續(xù)堅(jiān)持健身三個(gè)月早睡早起游戲時(shí)間大大縮減,學(xué)會(huì)生活。 上一篇:《你不知道的javascript》筆記_this 寫在前面 這是2019年第一篇博客,回顧去年年初列的學(xué)習(xí)清單,發(fā)現(xiàn)僅有部分完成了。當(dāng)然,這并不影響2018年是向上的一年:在新的城市穩(wěn)定、...
摘要:建筑的頂層代表全局作用域。實(shí)際的塊級(jí)作用域遠(yuǎn)不止如此塊級(jí)作用域函數(shù)作用域早期盛行的立即執(zhí)行函數(shù)就是為了形成塊級(jí)作用域,不污染全局。這便是閉包的特點(diǎn)吧經(jīng)典面試題下面的代碼輸出內(nèi)容答案?jìng)€(gè)如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫在前面 這一系列的筆記是在《javascript高級(jí)程序設(shè)計(jì)》讀書筆記系列的升華版本,旨在將零碎...
摘要:本書屬于基礎(chǔ)類書籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱不錯(cuò),下冊(cè)的知識(shí)點(diǎn)就這么少,非常不推介看下冊(cè)上中下三本的讀書筆記你不知道的上讀書筆記你不知道的中讀書筆記你不知道的下讀書筆記第三 本書屬于基礎(chǔ)類書籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱; 不錯(cuò),下冊(cè)的知識(shí)點(diǎn)就這么少,非...
摘要:但是如果非全局的變量如果被遮蔽了,無論如何都無法被訪問到。但是如果引擎在代碼中找到,就會(huì)完全不做任何優(yōu)化。結(jié)構(gòu)的分句中具有塊級(jí)作用域。第四章提升編譯器函數(shù)聲明會(huì)被提升,而函數(shù)表達(dá)式不會(huì)被提升。 本書屬于基礎(chǔ)類書籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱; 上中下三本的讀書筆記: 《你不知道的JavaScript》 (上) 讀書筆記...
摘要:隱式綁定即綁定到最頂層或最近調(diào)用對(duì)象上顯式綁定即用或手動(dòng)進(jìn)行綁定方法實(shí)現(xiàn)綁定構(gòu)造函數(shù)不存在其實(shí)在中不存在構(gòu)造函數(shù),我們所說的構(gòu)造函數(shù)其實(shí)就是普通的函數(shù),它只是用被構(gòu)造調(diào)用而已。 JS是編譯型語言 編譯發(fā)生在代碼執(zhí)行前幾微秒,簡(jiǎn)單來說就是js在執(zhí)行前要進(jìn)行編譯,編譯過程發(fā)生在代碼執(zhí)行前幾微妙,甚至更短。 編譯的步驟 詞法分析以var a = 2 為例,詞法分析會(huì)將其分成三個(gè)有意義的代碼...
閱讀 2816·2021-11-24 09:39
閱讀 1672·2021-09-28 09:35
閱讀 1148·2021-09-06 15:02
閱讀 1364·2021-07-25 21:37
閱讀 2797·2019-08-30 15:53
閱讀 3675·2019-08-30 14:07
閱讀 735·2019-08-30 11:07
閱讀 3553·2019-08-29 18:36