摘要:關鍵字是中一個復雜的機制,它被自動定義在所有的函數作用域中。指向它自身匿名函數無法指向自身第一個函數被稱為具名函數,在它內部可以使用來引用自身。的綁定和函數聲明的位置沒有任何關系,取決于函數的調用方式。這是理解的前提。
this關鍵字是JavaScript中一個復雜的機制,它被自動定義在所有的函數作用域中。
1. 為什么要用thisfunction identify() { return this.name.toUpperCase() } function speak() { var greeting = "hello, i"am" + identify.call(this) console.log(greeting) } var me = { name: "Kyle" } var you = { name: "Reader" } identify.call(me); //KYLE identify.call(you) //READER speak.call(me) //Hello, 我是KYLE speak.call(you) //Hello, 我是READER
上面這部分代碼在不同的上下文對象中重復使用identify()和speak(),不用針對每個對象編寫不同版本的函數。
如果不使用this,那就需要給identify()和speak()顯示傳入一個上下文對象。
function identify(context) { return context.name.toUpperCase(); } function speak(context) { var greeting = "Hello i"am" + identify(context) console.log(greeting) } identify(you) //READER speak(me) //hello, 我是KYLE
然而,this提供了一種更優雅的方式來隱式傳遞一個對象引用,因此可以將API設計的更加簡潔且易于復用。
當你的代碼越來越復雜的時候,顯示的傳遞上下文對象會變得很混亂。
通常會將this理解成指向函數自身。平常我們會在函數內部調用自身(例如遞歸)。在JavaScript中函數也是一個對象,那么我們可以在調用函數的時候存儲狀態(屬性的值)。
我們看下以下代碼,會發現this并沒有指向函數本身:
//記錄foo的調用次數 function foo(num) { console.log("foo: "+ num) this.count ++ } foo.count = 0; var i; for(i=0; i<10; i++) { if(i>5) { foo(i) } } //foo: 6 //foo: 7 //foo: 8 //foo: 9 //foo 被調用了多少次? console.log(foo.count) //0
可以看到foo()執行了4次,但是foo.count仍然是0,所以從字面上理解this指向的是當前函數自身就是錯誤的!
在執行foo.count=0的時候,確實向函數對象foo添加了一個count屬性,但是函數內部的this.count的this并不是指向那個函數對象(其實是window對象)。
那么增加的是哪個count?這是創建在全局變量的一個count,值為NaN.
如果要從函數對象內部引用它自身,那只使用this是不夠的。一般你需要通過一個指向函數對象的詞法標識符來引用。
function foo() { foo.count = 4 //foo指向它自身 } setTimeout(function() { //匿名函數無法指向自身 }, 10)
第一個函數被稱為具名函數,在它內部可以使用foo來引用自身。但是在第二個例子中,傳入setTimeout(..)的回調函數沒有名稱標識符,因此無法從函數內部引用自身。
還有一種方法是通過強制this指向foo函數對象:
function foo(num) { console.log("foo:" + num) this.count ++ } foo.count = 0 var i; for(i=0; i<10; i++) { if(i>5) { foo.call(foo, i) } }
如上,我們強制this指向了foo,這樣就可以獲得我們想要的答案了。
誤解之它的作用域第二種錯誤的理解是this指向函數的作用域。這個問題有些復雜,因為在某種情況下它是正確的。
需要明確的是,this在任何情況下都不指向函數的詞法作用域。在JavaScript內部,作用域確實很像對象,可見的標識符都是它的屬性。但是作用域對象是無法通過JavaScript代碼進行訪問,它是在JavaScript引擎內部。
function foo() { var a = 2; this.bar(); } function bar() { console.log(this.a) } foo(); // a is not defined
以上代碼運行是不會得到你理想的結果的,因為你不能使用this來引用一個詞法作用域內部的東西。
3. this到底是什么this是在運行時進行綁定的,并不是在編寫時綁定,它的上下文取決于函數調用時的各種條件。this的綁定和函數聲明的位置沒有任何關系,取決于函數的調用方式。
當一個函數調用時,會創建一個活動記錄(有時候也稱為執行上下文)。這個記錄 會包含函數在哪里被調用(調用棧),函數的調用方法,傳入的參數信息。this就是記錄的其中一個屬性,會在函數執行的過程中用到。
總結這里我們要明白this既不是指向函數自身,也不是指向函數的詞法作用域。這是理解this的前提。
this實際上時在函數被調用時發生的綁定,它指向什么完全取決于函數在哪里被調用。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/89948.html
摘要:找到函數的調用位置最重要的是要分析調用棧就是為了到達當前執行位置所調用的所有函數。顯示綁定我們可以使用函數的和方法,通過這兩個方法可以在某個對象上強制調用函數。 在上一篇我們了解過每個函數的this是在調用的時候綁定的,完全卻決于函數的調用位置(也就是函數的調用方法)。 1. 調用位置 在理解this的綁定過程之前,首先要理解調用位置:調用位置就是函數在代碼中被調用的位置,而不是聲明的...
摘要:下面開始分析開頭的代碼第一輪事件循環流程整體作為第一個宏任務進入主線程,遇到,輸出遇到函數聲明,聲明暫時不用管遇到,其回調函數被分發到微任務中。我們記為遇到,其回調函數被分發到宏任務中。 先上一道常見的筆試題 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 達到數據驅動界面,當然其中還有模板編譯等等其他...
閱讀 2885·2021-10-14 09:50
閱讀 1230·2021-10-08 10:21
閱讀 3663·2021-10-08 10:16
閱讀 3070·2021-09-27 14:02
閱讀 3146·2021-09-23 11:21
閱讀 2134·2021-09-07 10:17
閱讀 416·2019-08-30 14:00
閱讀 2121·2019-08-29 17:26