本章帶給大家Javascript中什麼是this? this的4種綁定方式(介紹)。有一定的參考價值,有需要的朋友可以參考一下,希望對你們有幫助。
什麼是this?
當一個函數被呼叫時,會建立一個活動記錄(有時候也稱為執行上下文)。這個記錄會包含函數在哪裡被呼叫(呼叫堆疊)、函數的呼叫方法、傳入的參數等資訊。 this就是記錄的其中一個屬性,會在函數執行的過程中被使用。
this的4種綁定方式
#預設綁定
function foo() { console.log( this.a ); } var a = 2; foo(); // 2
這段程式碼輸出2 , 說明this預設綁定到了全域物件
隱含綁定
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2
這段程式碼this綁定到了obj對象,當函數引用有上下文對象(context)時,隱式綁定規則會把this綁定到這個上下文物件。
隱含遺失問題
// 例子1111 function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函数别名!  var a = "oops, global"; // a是全局对象的属性” bar(); // "oops, global" //2222 function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var a = "oops, global"; // a是全局对象的属性 setTimeout( obj.foo, 100 ); // "oops, global
範例1111雖然bar是obj.foo的一個引用,但實際上,它引用的是foo函數本身,因此此時的bar()其實是一個不帶任何修飾的函數調用,因此應用了預設綁定。例子222在setTimeout函數中遺失了this綁定,道理是一樣的,我們可以把參數傳遞看成一種隱式賦值。
明確綁定
在分析隱含綁定時,我們必須在一個物件內部包含一個指向函數的屬性,並透過這個屬性間接引用函數,從而把this間接(隱式)綁定到這個物件上。
那麼如果我們不想在物件內部包含函數引用,而想在某個物件上強制呼叫函數,該怎麼做呢?
學過js的估計對 call,apply和bind都不陌生,js提供的這些原生方法就給我們提供了明確綁定this的途徑。
function foo() { console.log( this.a ); }var obj = { a:2}; foo.call( obj ); // 2
透過foo.call(..),我們可以在呼叫foo時強制把它的this綁定到obj上。
如果你傳入了一個原始值(字串型別、布林型別或數字型別)來當作this的綁定對象,這個原始值會被轉換成它的物件形式(也就是new String (..)、new Boolean(..)或new Number(..))。這通常被稱為“裝箱”。
「從this綁定的角度來說,call(..)和apply(..)是一樣的,它們的區別體現在其他的參數上,但是現在我們不用考慮這些。」
硬綁定-bind的實作
我們已經知道this綁定的4種方式,但是使用call和apply我們還是無法解決隱式遺失的問題,思考以下例子:
function foo() { console.log( this.a ); } var obj = { a:2 }; var bar = function() { foo.call( obj ); }; bar(); // 2 setTimeout( bar, 100 ); // 2 bar.call(windows) //无法再修改this
透過call我們在函數bar內強制指定了foo的this,之後不論如何呼叫bar,它總會在obj上手動呼叫foo,這種綁定是一種顯示強制綁定,因此稱為硬綁定。這就是bind的產生來由(因為硬綁定比較常用,es5中新增了bind方法),透過硬綁定製定this,上面程式碼現在就變成了
...略var bar = foo.bind(obj) bar(); // 2setTimeout( bar, 100 ); // 2
綁定規則優先權和es6的this新特性
如果要判斷一個運行中函數的this綁定,就需要找到這個函數的直接呼叫位置。找到之後就可以順序應用下面這四條規則來判斷this的綁定物件。
由new呼叫?綁定到新建立的物件。
由call或apply(或bind)呼叫?綁定到指定的物件。
由上下文物件呼叫?綁定到那個上下文物件。
預設:在嚴格模式下綁定到undefined,否則綁定到全域物件。
幾個小例子看懂this
unction showThis () { console.log(this) }function showStrictThis () { 'use strict' console.log(this) } showThis() // windowshowStrictThis() // undefined
優先權最小的this對象,預設綁定。
思考下面的例子:
var person = { name: '11', showThis () { return this } } person.showThis() === person //truevar person2 = { name: '22', showThis () { return person.showThis() } }var person3 = { name: '33', showThis () { var retrunThis = person.showThis return retrunThis() } } person.showThis() //personperson2.showThis() //?person3.showThis() //?
我們首先要找到呼叫位置,在2裡是這句return person.showThis(),隱式綁定了一個person對象,所以輸出person ,3 是return retrunThis() ,this預設綁定到全域,返回window.
function showThis () { return this } var person = { name: 'person' } showThis() // window showThis.call(p1) // person showThis.apply(p1) // person
透過明確綁定指定了context object。
function showThis () { return this } var person = { name: 'person' } var personBind = showThis.bind(person) personBind() //person var person2 = { name: 'person2' } personBind.call(person2) //person
bind方法強綁定了this,已經無法再透過明確綁定切換this。
function showThis () { return this } var person = { name: 'person' } var person2 = { name: 'person2' } var personBind = showThis.bind(person) personBind() //person new personBind() //showThis
new優先權高於bind,所以可以覆寫this。
function foo() { setTimeout(() => { // 这里的this在词法上继承自foo() console.log( this.a ); },100); }var obj = { a:2}; foo.call( obj ); // 2
箭頭函數並不是使用function關鍵字定義的,而是使用被稱為「胖箭頭」的運算子=>定義的。箭頭函數不使用this的四種標準規則,而是根據外層(函數或全域)作用域來決定this。箭頭函數的綁定無法被修改,包括new。關於箭頭函數網路上有許多詳細全面的講解。這裡不再展開。
以上是Javascript中什麼是this? this的4種綁定方式(介紹)的詳細內容。更多資訊請關注PHP中文網其他相關文章!