亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript中this的綁定你知道幾種?

 更新時(shí)間:2023年02月08日 11:35:11   作者:mick  
this對(duì)于一些有經(jīng)驗(yàn)的JavaScript開(kāi)發(fā)者來(lái)說(shuō)是一種非常復(fù)雜的機(jī)制。并且很多開(kāi)發(fā)者對(duì)于this的理解并不是很清晰,導(dǎo)致在面試的時(shí)候經(jīng)常受挫。今天我們就來(lái)看一看這個(gè)this真的有那么難嗎

執(zhí)行上下文

我們知道執(zhí)行上下文分為兩種:全局上下文和函數(shù)上下文(我的這篇文章對(duì)于執(zhí)行上下文有講解還對(duì)執(zhí)行上下文和作用域迷糊嗎?)。全局上下文只有一個(gè),函數(shù)執(zhí)行上下文是在函數(shù)調(diào)用的時(shí)候創(chuàng)建的。

每個(gè)執(zhí)行上下文都有三個(gè)屬性:

  • 變量對(duì)象
  • 作用域鏈
  • this

this到底是什么呢

this是在運(yùn)行時(shí)綁定的,并不是在編寫(xiě)時(shí)綁定的,它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件。this的綁定和函數(shù)聲明的位置沒(méi)有任何的關(guān)系,只取決于函數(shù)的調(diào)用方式。

調(diào)用位置

要理解this的綁定過(guò)程,首先要理解調(diào)用位置。調(diào)用位置就是函數(shù)的調(diào)用的位置(不是聲明的位置)。所以我們要先來(lái)分析調(diào)用棧(也就是執(zhí)行上下文棧)。我們先來(lái)看一段代碼。

function baz() {
  console.log("baz")
  bar()
}
function bar() {
  console.log("bar")
  foo()
}
function foo() {
  console.log("foo")
}
baz()

當(dāng)代碼執(zhí)行到foo(),進(jìn)入foo的函數(shù)體,此時(shí)當(dāng)前的調(diào)用棧為:

ECStack = [
    fooContext, // foo
    barContext, // bar
    bazContext, // baz
    globalContext, // 全局
]

通過(guò)調(diào)用棧我們就可以很清晰的找到函數(shù)的調(diào)用位置。baz在全局調(diào)用,bar在baz里調(diào)用,foo在bar里調(diào)用。

那函數(shù)在執(zhí)行的時(shí)候是如何決定this的綁定對(duì)象的呢?

綁定規(guī)則

通過(guò)綁定規(guī)則決定this的綁定對(duì)象。

默認(rèn)綁定

最常用的調(diào)用類(lèi)型:獨(dú)立函數(shù)調(diào)用。

function foo(){
    console.log(this.a) // 2
}

var a = 2;
foo()

函數(shù)調(diào)用的時(shí)候,使用了this的默認(rèn)綁定,因此this指向全局對(duì)象。

那么我們?cè)趺粗肋@里應(yīng)用了默認(rèn)綁定呢?可以通過(guò)分析調(diào)用位置來(lái)看看 foo() 是如何調(diào)用的。在代碼中,foo()是直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用的,因此只能使用默認(rèn)綁定,無(wú)法應(yīng)用其他規(guī)則。

所以,在全局環(huán)境中調(diào)用一個(gè)函數(shù),函數(shù)內(nèi)部的this指向的是全局變量window。

隱式綁定

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2,
    foo: foo
};

obj.foo(); // 2

這段代碼我們看到foo的聲明位置是在全局的,但是它被當(dāng)做引用屬性添加到了obj中。調(diào)用位置使用obj上下文引用函數(shù)。當(dāng)foo被調(diào)用時(shí)候,它是被obj對(duì)象所包含的,落腳點(diǎn)指向obj對(duì)象。當(dāng)函數(shù)引用有上下文對(duì)象時(shí),隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對(duì)象。

通過(guò)一個(gè)對(duì)象調(diào)用其內(nèi)部的一個(gè)方法,該方法的執(zhí)行上下文中的this指向?qū)ο蟊旧?/strong>

我們看個(gè)特殊的例子

function foo() {
  console.log(this.a)
}

var obj = {
  a: 2,
  foo
}

var bar = obj.foo
var a = "mick"
bar() // mick

bar是obj.foo的一個(gè)引用,但是實(shí)際上,它引用的是foo函數(shù)本身,因此此時(shí)bar()其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用,因此應(yīng)用了默認(rèn)綁定。

我們?cè)倏戳硪环N情況

function foo() {
  console.log(this.a)
}

function doFoo(fn) {
  fn()
}

var obj = {
  a: 2,
  foo
}

var a = "mick"

doFoo(obj.foo) // mick

嵌套函數(shù)中的this 不會(huì)從外層函數(shù)中繼承。this永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象

顯示綁定

可以使用call、apply或bind方法。如果對(duì)這三個(gè)方法的實(shí)現(xiàn)原理感興趣可以看看這篇手寫(xiě)call、apply、bind

function foo() {
  console.log(this.a)
}
var obj = {
  a: 2
}

foo.call(obj) // 2

通過(guò)call方法,可以在調(diào)用foo時(shí)候,強(qiáng)制把它的this綁定到obj上。

new綁定

這里我們先說(shuō)一下new來(lái)調(diào)用函數(shù)會(huì)發(fā)生哪些事情

  • 創(chuàng)建一個(gè)全新的對(duì)象
  • 這個(gè)新對(duì)象會(huì)被執(zhí)行[[原型]]鏈接
  • 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this
  • 如果函數(shù)沒(méi)有返回其他對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
function foo(a){
    this.a = a
}
var bar = new foo(2)
console.log(bar.a)

使用new來(lái)調(diào)用foo時(shí),我們會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到foo調(diào)用中的this上。

特例

function foo() {
  console.log(this.a)
}

var a = 2
var o = { a: 3, foo: foo }
var p = { a: 4 }

o.foo() // 3
;(p.foo = o.foo)() // 2

賦值表達(dá)式p.foo = o.foo的返回值是目標(biāo)函數(shù)的引用,因此調(diào)用位置是foo()而不是p.foo()或者o.foo()。所以這里是默認(rèn)綁定。

面試題

下面我們看個(gè)面試題吧

var name = 'window'
var person1 = {
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    return () => {
      console.log(this.name)
    }
  }
}
var person2 = { name: 'person2' }

person1.foo1()
person1.foo1.call(person2)

person1.foo2()
person1.foo2.call(person2)

person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)

person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)

我們一個(gè)個(gè)來(lái)解析一下。

  • person.foo1()這個(gè)屬于隱式綁定,foo1的this綁定到了person,所以打印person1
  • person1.foo1.call(person2)顯示綁定,foo1的this通過(guò)call改變了this,指向了person,所以打印person2
  • person.foo2()因?yàn)閒oo2是箭頭函數(shù),所以它的this指向是它上一層this的指向也就是window,window
  • person1.foo2.call(person2)和上面一條同樣的道理,也是window
  • person1.foo3()()內(nèi)部返回了一個(gè)函數(shù),其實(shí)是一個(gè)函數(shù)的引用,此時(shí)this應(yīng)該指向window,所以打印window
  • person1.foo3.call(person2)()通過(guò)call只是改變了foo3的this指向,和返回的函數(shù)沒(méi)有什么關(guān)系,所以this還是指向window,打印window
  • person1.foo3().call(person2)通過(guò)call改變了foo3內(nèi)部返回函數(shù)的this指向,所以打印person2
  • person1.foo4()()返回的是一個(gè)箭頭函數(shù),箭頭函數(shù)的this是它上一層函數(shù)內(nèi)部this的指向,所以也就是foo4this的指向,由于foo4被person1包含并調(diào)用,所以this指向person1,打印person1
  • person1.foo4.call(person2)(),此時(shí)foo4內(nèi)部的this通過(guò)call改變成了person2,所以打印person
  • person1.foo4().call(person2)這個(gè)和person1.foo4()是一樣的道理,打印person1

簡(jiǎn)單的談了談this的綁定,歡迎留言你的問(wèn)題,大家一起學(xué)習(xí)一起進(jìn)步?。。?/p>

到此這篇關(guān)于JavaScript中this的綁定你知道幾種?的文章就介紹到這了,更多相關(guān)JavaScript this綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論