欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2023年02月08日 11:35:11   作者:mick  
this對于一些有經驗的JavaScript開發(fā)者來說是一種非常復雜的機制。并且很多開發(fā)者對于this的理解并不是很清晰,導致在面試的時候經常受挫。今天我們就來看一看這個this真的有那么難嗎

執(zhí)行上下文

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

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

  • 變量對象
  • 作用域鏈
  • this

this到底是什么呢

this是在運行時綁定的,并不是在編寫時綁定的,它的上下文取決于函數調用時的各種條件。this的綁定和函數聲明的位置沒有任何的關系,只取決于函數的調用方式。

調用位置

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

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

當代碼執(zhí)行到foo(),進入foo的函數體,此時當前的調用棧為:

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

通過調用棧我們就可以很清晰的找到函數的調用位置。baz在全局調用,bar在baz里調用,foo在bar里調用。

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

綁定規(guī)則

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

默認綁定

最常用的調用類型:獨立函數調用。

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

var a = 2;
foo()

函數調用的時候,使用了this的默認綁定,因此this指向全局對象。

那么我們怎么知道這里應用了默認綁定呢?可以通過分析調用位置來看看 foo() 是如何調用的。在代碼中,foo()是直接使用不帶任何修飾的函數引用進行調用的,因此只能使用默認綁定,無法應用其他規(guī)則。

所以,在全局環(huán)境中調用一個函數,函數內部的this指向的是全局變量window。

隱式綁定

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

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

obj.foo(); // 2

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

通過一個對象調用其內部的一個方法,該方法的執(zhí)行上下文中的this指向對象本身

我們看個特殊的例子

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

var obj = {
  a: 2,
  foo
}

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

bar是obj.foo的一個引用,但是實際上,它引用的是foo函數本身,因此此時bar()其實是一個不帶任何修飾的函數調用,因此應用了默認綁定。

我們再看另一種情況

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

function doFoo(fn) {
  fn()
}

var obj = {
  a: 2,
  foo
}

var a = "mick"

doFoo(obj.foo) // mick

嵌套函數中的this 不會從外層函數中繼承。this永遠指向最后調用它的那個對象

顯示綁定

可以使用call、apply或bind方法。如果對這三個方法的實現原理感興趣可以看看這篇手寫call、apply、bind

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

foo.call(obj) // 2

通過call方法,可以在調用foo時候,強制把它的this綁定到obj上。

new綁定

這里我們先說一下new來調用函數會發(fā)生哪些事情

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

使用new來調用foo時,我們會構造一個新對象并把它綁定到foo調用中的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

賦值表達式p.foo = o.foo的返回值是目標函數的引用,因此調用位置是foo()而不是p.foo()或者o.foo()。所以這里是默認綁定。

面試題

下面我們看個面試題吧

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)

我們一個個來解析一下。

  • person.foo1()這個屬于隱式綁定,foo1的this綁定到了person,所以打印person1
  • person1.foo1.call(person2)顯示綁定,foo1的this通過call改變了this,指向了person,所以打印person2
  • person.foo2()因為foo2是箭頭函數,所以它的this指向是它上一層this的指向也就是window,window
  • person1.foo2.call(person2)和上面一條同樣的道理,也是window
  • person1.foo3()()內部返回了一個函數,其實是一個函數的引用,此時this應該指向window,所以打印window
  • person1.foo3.call(person2)()通過call只是改變了foo3的this指向,和返回的函數沒有什么關系,所以this還是指向window,打印window
  • person1.foo3().call(person2)通過call改變了foo3內部返回函數的this指向,所以打印person2
  • person1.foo4()()返回的是一個箭頭函數,箭頭函數的this是它上一層函數內部this的指向,所以也就是foo4this的指向,由于foo4被person1包含并調用,所以this指向person1,打印person1
  • person1.foo4.call(person2)(),此時foo4內部的this通過call改變成了person2,所以打印person
  • person1.foo4().call(person2)這個和person1.foo4()是一樣的道理,打印person1

簡單的談了談this的綁定,歡迎留言你的問題,大家一起學習一起進步!??!

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

相關文章

最新評論