摘要:找到函數(shù)的調(diào)用位置最重要的是要分析調(diào)用棧就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。顯示綁定我們可以使用函數(shù)的和方法,通過(guò)這兩個(gè)方法可以在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù)。
在上一篇我們了解過(guò)每個(gè)函數(shù)的this是在調(diào)用的時(shí)候綁定的,完全卻決于函數(shù)的調(diào)用位置(也就是函數(shù)的調(diào)用方法)。
1. 調(diào)用位置在理解this的綁定過(guò)程之前,首先要理解調(diào)用位置:調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置,而不是聲明的位置。
找到函數(shù)的調(diào)用位置最重要的是要分析調(diào)用棧(就是為了到達(dá)當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù))。我們關(guān)心的調(diào)用位置就在當(dāng)前正在執(zhí)行的函數(shù)的前一個(gè)調(diào)用中。
function baz() { //當(dāng)前調(diào)用棧是:baz //因此,當(dāng)前調(diào)用位置是全局作用域 console.log("baz"); bar(); //<--bar的調(diào)用位置 } function bar() { //當(dāng)前調(diào)用棧是baz->bar //因此,當(dāng)前調(diào)用位置在baz中 console.log("bar") foo(); } function foo() { //當(dāng)前調(diào)用棧是baz->bar->foo //因此,當(dāng)前調(diào)用位置在bar中 console.log("foo") } baz() //<---baz得調(diào)用位置2. 綁定規(guī)則
那么調(diào)用位置如何決定this得綁定對(duì)象呢。首先,我們要找到調(diào)用位置,然后按照下面四條規(guī)則進(jìn)行應(yīng)用。首先我們先了解下這幾條規(guī)則:
(1)默認(rèn)綁定首先介紹最常用得函數(shù)調(diào)用類型:獨(dú)立函數(shù)調(diào)用。可以將這條規(guī)則看作是無(wú)法應(yīng)用其他規(guī)則得默認(rèn)規(guī)則。
function foo() { console.log(this.a) } var a = 2; foo(); //2
上面得代碼中,在全局環(huán)境中聲明了一個(gè)變量a,那么a就是全局對(duì)象得一個(gè)同名屬性。當(dāng)調(diào)用foo()時(shí),this.a被解析成了全局變量a。因?yàn)楹瘮?shù)調(diào)用得時(shí)候應(yīng)用了this得默認(rèn)綁定,因此this指向全局對(duì)象。
在代碼中,foo()是直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用,因此只能使用默認(rèn)綁定。
如果使用嚴(yán)格模式,那么全局對(duì)象將無(wú)法使用默認(rèn)綁定,因此this會(huì)綁定到undefined。
(2)隱式綁定另一條需要考慮的規(guī)則是調(diào)用位置是否有上下文對(duì)象,或則說(shuō)是否被某個(gè)對(duì)象擁有或者包含。
function foo() { console.log(this.a) } var obj = { a: 2, foo: foo } obj.foo(); //2
首先需要注意的是foo()的聲明方式,以及之后是如何被當(dāng)作引用屬性添加到obj中的。但是無(wú)論是直接在obj定義還是先定義再添加為引用屬性,這個(gè)函數(shù)嚴(yán)格來(lái)說(shuō)都不屬于obj對(duì)象。
調(diào)用位置會(huì)使用obj上下文來(lái)引用函數(shù),因此你可以說(shuō)函數(shù)被調(diào)用時(shí),obj對(duì)象"擁有"或者"包含"它。
當(dāng)foo()調(diào)用時(shí),它的落腳點(diǎn)確實(shí)指向obj對(duì)象。當(dāng)函數(shù)引用有上下文對(duì)象時(shí),隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對(duì)象。因?yàn)檎{(diào)用foo()時(shí)this被綁定到obj,因此this.a和obj.a時(shí)一樣的。
對(duì)象屬性引用鏈中只有最頂層或者最后一層會(huì)影響調(diào)用位置。
function foo() { console.log(this.a) } var obj2 = { a: 42, foo: foo } var obj1 = { a: 2, obj2: obj2 } obj1.obj2.foo() //42
隱式丟失
this綁定一個(gè)常見的問(wèn)題就是被隱式綁定的函數(shù)會(huì)丟失綁定對(duì)象,也就是說(shuō)它會(huì)應(yīng)用默認(rèn)綁定,從而把this綁定到全局對(duì)象或者undefined上,這要取決于是否式嚴(yán)格模式。
function foo() { console.log(this.a) } var obj = { a:2, foo: foo } var bar = obj.foo; //函數(shù)別名 var a = "oops, globas"; //a式全局對(duì)象的屬性 bar(); //"oops, globas"
雖然bar是obj.foo的引用,但實(shí)際上,它引用的是foo函數(shù)本身,因此此時(shí)的bar()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,因此應(yīng)用默認(rèn)綁定。
再看下面一組代碼:
function foo() { console.log(this.a) } function doFoo(fn) { fn(); } var obj = { a:2, foo:foo } var a = "oops,global" doFoo(obj.foo); //"oops, global"
參數(shù)傳遞其實(shí)就是一種隱式賦值,因此我們傳入函數(shù)時(shí)也會(huì)被隱式賦值,所以結(jié)果和之前一樣。
(3)顯示綁定我們可以使用函數(shù)的call()和apply()方法,通過(guò)這兩個(gè)方法可以在某個(gè)對(duì)象上強(qiáng)制調(diào)用函數(shù)。
這兩個(gè)方法的作用都是一樣的,第一個(gè)參數(shù)是一個(gè)對(duì)象,它們會(huì)把這個(gè)對(duì)象綁定到this,接著在調(diào)用函數(shù)時(shí)指定這個(gè)this。因?yàn)榭梢灾苯又付╰his的綁定對(duì)象,因此叫做顯示綁定。
function foo() { console.log(this.a) } var obj = { a: 2 } foo.call(obj); //2
通過(guò)foo.call(..),我們可以在調(diào)用foo時(shí)強(qiáng)制把它的this綁定到obj上。
如果你傳入了一個(gè)原始值(字符串類型,布爾類型等)來(lái)當(dāng)作this的綁定對(duì)象,這個(gè)原始值會(huì)被轉(zhuǎn)換成對(duì)象形式,也就是(new String(..)),這通常被稱為"裝箱"。
function foo() { console.log(this.a) } var obj = { a:2 } var bar = function() { foo.call(obj) } bar();//2 setTimeout(bar, 10); //2 bar.call(window); //2
如上,我們不管怎么調(diào)用bar,它總會(huì)手動(dòng)在obj上調(diào)用foo,這種綁定時(shí)一種顯示的強(qiáng)制綁定,因此我們稱為為硬綁定。
硬綁定的典型應(yīng)用場(chǎng)景就是創(chuàng)建一個(gè)包裹函數(shù),傳入所有的參數(shù)并返回接收到的所有值:
function foo(something) { console.log(this.a, something) return this.a + something } //簡(jiǎn)單的輔助綁定函數(shù) function bind(fn, obj) { return function() { return fn.apply(obj, arguments) } } var obj = { a: 2 }; var bar = bind(foo, obj) var b = bar(3) //2, 3 console.log(b) //5
bind(...)會(huì)返回一個(gè)硬編碼的新函數(shù),它會(huì)把參數(shù)設(shè)置為this的上下文并調(diào)用原始函數(shù)。
(4) new綁定在JavaScript中,構(gòu)造函數(shù)只是一些使用new操作符時(shí)被調(diào)用的函數(shù)。他們并不會(huì)屬于某個(gè)類,也不會(huì)實(shí)例化一個(gè)類。實(shí)際上他們甚至都不能說(shuō)時(shí)一種特殊的函數(shù)類型。只是被new操作符調(diào)用的普通函數(shù)。
使用new來(lái)調(diào)用函數(shù)時(shí)會(huì)執(zhí)行以下操作:
1. 創(chuàng)建一個(gè)全新的對(duì)象 2. 這個(gè)新對(duì)象會(huì)被執(zhí)行[[原型]]連接 3. 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this 4. 如果函數(shù)沒有返回其他對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90022.html
摘要:關(guān)鍵字是中一個(gè)復(fù)雜的機(jī)制,它被自動(dòng)定義在所有的函數(shù)作用域中。指向它自身匿名函數(shù)無(wú)法指向自身第一個(gè)函數(shù)被稱為具名函數(shù),在它內(nèi)部可以使用來(lái)引用自身。的綁定和函數(shù)聲明的位置沒有任何關(guān)系,取決于函數(shù)的調(diào)用方式。這是理解的前提。 this關(guān)鍵字是JavaScript中一個(gè)復(fù)雜的機(jī)制,它被自動(dòng)定義在所有的函數(shù)作用域中。 1. 為什么要用this function identify() { ...
摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...
摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...
摘要:是什么本質(zhì)是一個(gè)綁定,在函數(shù)被調(diào)用時(shí)建立。它的指向是完全由函數(shù)被調(diào)用的調(diào)用點(diǎn)來(lái)決定的。因?yàn)楹瘮?shù)的調(diào)用點(diǎn)在全局作用域,所以指向全局變量這里就是函數(shù)的調(diào)用點(diǎn)存在的意義在函數(shù)體內(nèi)部指代函數(shù)當(dāng)前的運(yùn)行環(huán)境。從而實(shí)現(xiàn)干凈的設(shè)計(jì)和更容易的復(fù)用。 this是什么? this 本質(zhì)是一個(gè)綁定, 在函數(shù)被調(diào)用時(shí)建立。它的指向是完全由函數(shù)被調(diào)用的調(diào)用點(diǎn)來(lái)決定的。 function baz() { ...
摘要:而小程序官方的是在中調(diào)用方法來(lái)改變數(shù)據(jù),從而改變界面。為了寫測(cè)試讓咱們來(lái)重構(gòu)一把,利用學(xué)習(xí)過(guò)的函數(shù)式編程中的高階函數(shù)把依賴注入。也就是說(shuō)當(dāng)中的某個(gè)數(shù)據(jù)更新的時(shí)候,我們并不知道它會(huì)影響哪個(gè)中的屬性,特別的還有依賴于的情況。 眾所周知 Vue 是借助 ES5 的 Object.defineProperty 方法設(shè)置 getter、setter 達(dá)到數(shù)據(jù)驅(qū)動(dòng)界面,當(dāng)然其中還有模板編譯等等其他...
閱讀 1278·2021-11-23 09:51
閱讀 1637·2021-11-16 11:45
閱讀 4072·2021-10-09 09:43
閱讀 2697·2021-07-22 16:47
閱讀 957·2019-08-27 10:55
閱讀 3461·2019-08-26 17:40
閱讀 3099·2019-08-26 11:39
閱讀 3238·2019-08-23 18:39