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