箭頭函數和 this指向

this 是和執行上下文綁定的,也就是說每個執行上下文中都有一個 this。
在這裏插入圖片描述
上圖中 outer 是在變量環境裏面的,爲了方便看

我們都知道 js 在編譯階段 創建執行上下文
在每個執行上下文的變量環境中,都包含了一個外部引用,用來指向外部的執行上下文,我們把這個外部引用稱爲 outer

全局執行上下文中的 this:

全局執行上下文中的 this 是指向 window 對象的。這也是 this 和作用域鏈的唯一交點,作用域鏈的最底端包含了 window 對象,全局執行上下文中的 this 也是指向 window 對象

函數中的this:

function foo(){
  console.log(this)
}
foo()
// 也是指向window

那能不能設置執行上下文中的 this 來指向其他對象呢? 肯定是可以的

1、通過函數的 call 方法設置:

let bar = {
  myName : "極客邦",
  test1 : 1
}
function foo(){
  this.myName = "極客時間"
}
foo.call(bar)
console.log(bar)   // {myName: "極客時間", test1: 1}
console.log(myName)   // myName is not defined

你就能發現 foo 函數內部的 this 已經指向了 bar 對象,
因爲通過打印 bar 對象,可以看出 bar 的 myName 屬性已經由“極客邦”變爲“極客時間”了,
同時在全局執行上下文中打印 myName, myName is not defined

2、通過對象調用方法設置:

要改變函數執行上下文中的 this 指向,除了通過函數的 call 方法來實現外,還可以通過對象調用的方式

var myObj = {
  name : "極客時間", 
  showThis: function(){
    console.log(this)
  }
}
myObj.showThis()  // {name: "極客時間", showThis: ƒ}

使用對象來調用其內部的一個方法,該方法的 this 是指向對象本身的。

var myObj = {
  name : "極客時間",
  showThis: function(){
    this.name = "極客邦"
    console.log(this)
  }
}
var foo = myObj.showThis
foo()
//你會發現 this 又指向了全局 window 對象。
  • 在全局環境中調用一個函數,函數內部的 this 指向的是全局變量 window。
  • 通過一個對象來調用其內部的一個方法,該方法的執行上下文中的 this 指向對象本身。

3. 通過構造函數中設置:

function CreateObj(){ 
this.name = "極客時間"
console.log(this)   // CreateObj {name: "極客時間"}
}
var myObj = new CreateObj()

new CreateObj() 過程:

1、首先創建了一個空對象 tempObj;
2、接着調用 CreateObj.call 方法,並將 tempObj 作爲 call 方法的參數,這樣當 CreateObj 的執行上下文創建時,它的 this 就指向了 tempObj 對象;
3、然後執行 CreateObj 函數,此時的 CreateObj 函數執行上下文中的 this 指向了 tempObj 對象;
4、最後返回 tempObj 對象。

嵌套函數中的 this 不會從外層函數中繼承

var myObj = {
  name : "極客時間", 
  showThis: function(){
    console.log(this) 
    function bar(){console.log(this)}
    bar()
  }
}
myObj.showThis()
//函數 bar 中的 this 指向的是全局 window 對象,
// 而函數 showThis 中的 this 指向的是 myObj 對象

那怎麼實現 bar 的this指向外層 myObj 呢?

var myObj = {
  name : "極客時間", 
  showThis: function(){
    console.log(this)
    var self = this
    function bar(){
      self.name = "極客邦"
    }
    bar()
  }
}
myObj.showThis()
console.log(myObj.name)
console.log(window.name)

本質是把 this 體系轉換爲了作用域的體系 。也可以使用 ES6 中的箭頭函數來解決這個問題

var myObj = {
  name : "極客時間", 
  showThis: function(){
    console.log(this) // {name: "極客時間", showThis: ƒ}
    var bar = ()=>{
      this.name = "極客邦"
      console.log(this)  //  {name: "極客邦", showThis: ƒ}
    }
    bar()
  }
}
myObj.showThis()  
console.log(myObj.name)   // 極客邦
console.log(window.name)  //  ''

因爲 ES6 中的箭頭函數並不會創建其自身的執行上下文,所以箭頭函數中的 this 取決於它的外部函數

  • 當函數作爲對象的方法調用時,函數中的 this 就是該對象;
  • 當函數被正常調用時,在嚴格模式下,this 值是 undefined,非嚴格模式下 this 指向的是全局對象 window;
  • 嵌套函數中的 this 不會繼承外層函數的 this 值

箭頭函數和普通函數的區別:

箭頭函數和普通函數的this:

1、this 指向不同:

  • 普通函數this 指向 爲方法調用的對象,可以通過bind,call,apply,改變this指向
  • 箭頭函數比函數表達式更簡潔,箭頭函數不會創建自己的this,它只會從自己的作用域鏈的上一層繼承this。bind,call,apply只能調用傳遞參數,不可修改this指向
var obj = {
  a: 10,
  b: () => {
    console.log(this.a); // undefined
    console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
  },
  c: function() {
    console.log(this.a); // 10
    console.log(this); // {a: 10, b: ƒ, c: ƒ}
  }
}
obj.b(); 
obj.c();

箭頭函數不綁定this,會捕獲其所在的上下文的this值,作爲自己的this值。
任何方法都改變不了其指向

var obj = {
  a: 10,
  b: function(){
    console.log(this.a); //10
  },
  c: function() {
     return ()=>{
           console.log(this.a); //10
     }
  }
}
obj.b(); 
obj.c()();

箭頭函數通過 call() 或 apply() 方法調用一個函數時,只傳入了一個參數,對 this 並沒有影響。

補充:call,aplly,bind:
它們在功能上是沒有區別的,都是改變this的指向,它們的區別主要是在於方法的實現形式和參數傳遞上的不同。call和apply方法都是在調用之後立即執行的。而bind調用之後是一個函數,需要再調用一次纔行,
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章