首頁  >  文章  >  web前端  >  Javascript中什麼是this? this的4種綁定方式(介紹)

Javascript中什麼是this? this的4種綁定方式(介紹)

青灯夜游
青灯夜游原創
2018-09-21 17:19:222223瀏覽

本章帶給大家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的綁定物件。

  1. 由new呼叫?綁定到新建立的物件。

  2. 由call或apply(或bind)呼叫?綁定到指定的物件。

  3. 由上下文物件呼叫?綁定到那個上下文物件。

  4. 預設:在嚴格模式下綁定到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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn