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