JS 總結之關於 this 應該知道的幾個點

圖片描述

JS 中的 this 對每位前端工程師都不陌生,常常看到對象這裏 this 那裏 this,那什麼是 this?答案就是上下文對象,即被調用函數所處的環境,也就是說,this 在函數內部指向了調用函數的對象。前端

通俗的講,就是誰調用了函數es6

🐃 狀況 1

this 指向 window數組

var name = 'xiaoming' // 思考,爲何不能用 let 或者 const ?
function foo () {
  console.log(this.name)
}
foo() // xiaoming

誰調用了這個函數,答案就是 window。這好理解,由於這裏的變量和函數都是直接掛在 window 上的,等同於 window.foo()。需注意,嚴格模式下,this 爲 undefined前端工程師

🐏 狀況 2

this 指向一個對象app

var name = 'xiaoming'
var foo = {
  name: 'Jon',
  getName () {
    console.log(this.name)
  }
}
foo.getName() // Jon

誰調用了這個函數,答案是 foo 對象,因此打印了 Jon 而不是 xiaoming函數

var bar = foo.getName
bar() // xiaoming

若是賦值到另外一個變量,就變成 window 調用,因此打印了 xiaomingpost

🐎 狀況 3

this 指向了一個用 new 新生成的對象this

function Person (name) {
  this.name = name
  this.getName = function () {
    console.log(this.name)
  }
}

var jser = new Person('Jon')
jser.getName() // Jon

這種方式成爲 new 綁定,也叫作構造調用spa

JavaScript 中,new 的機制實際上和麪向類的語言徹底不一樣,構造函數只是一些使用 new 操做符時被調用的函數,它們並不會屬於某個類,也不會實例化一個類。prototype

實際上,除 ES6 的 Symbol()外,全部函數均可以用 new 來調用,因此並不存在所謂的構造函數,只有對於函數進行構造調用

使用 new 來調用函數,或者說發生構造函數調用時,會自動執行下面的操做:

  1. 建立(或者說構造)一個全新的對象
  2. 這個新對象會被執行原型連接
  3. 這個新對象會綁定到函數調用的 this
  4. 若是函數沒有返回其餘對象,那麼 new 表達式中的函數調用會自動返回這個新對象

這個例子中,使用 new 來調用 Person(..) 時,咱們會構造一個新對象(jser)並把它綁定到 Person(..) 調用中的 this 上。
或者能夠這麼想,誰調用了 getName ?就是 jser 調用了,因此 this 指向了 jser

🦍 狀況 4

用 call,apply 和 bind 來修改 this 指向

🍎 call / apply

call 和 apply 是以不一樣對象做爲上下文對象來調用某個函數,舉個例子:

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

var foo = {
  name: 'foo'
}

bar.getName.call(foo) // foo

看起來像是借用函數,對象 foo 借用了 bar 的函數 getName,因此咱們判斷一個對象類型,常常這麼搞:

let foo = [1,2,3,4,5]
Object.prototype.toString.call(foo) // "[object Array]"

apply 和 call 的用法同樣,不一樣點在於 call 用參數表給調用函數傳參,而 apply 使用了數組

🍉 bind

bind 能夠永久性的修改函數中的 this 的指向,不管誰調用,this 指向都同樣,並返回了完成綁定的函數,看例子:

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

var foo = {
  name: 'foo'
}

foo.func = bar.getName.bind(bar)
foo.func() // bar

這裏的 func 不受 foo 影響,this 仍是指向了 bar

var bar = {
  name: 'bar',
  getName () {
    console.log(this.name)
  }
}

func = bar.getName.bind(bar)
func() // bar

這裏的 func 也不受 window 影響,this 仍是指向了 bar

綜合上述,bind 強制修改了 this,誰調用了函數 this 都不能被修改

🍒 忽略 this

若是你把 null 或者 undefined 做爲 this 的綁定對象傳入 call、apply 或者 bind,這些值再調用時會被忽略,實際應用的是默認綁定。

🐆 箭頭函數

ES6 中介紹了一種沒法使用這些規則的特殊函數類型:箭頭函數,根據外層(函數或者全局)做用域來決定 this,箭頭函數經常使用於回調函數

🐣 狀況 1 中,爲何不能用 let 聲明?

ES6 中,let 命令、const 命令、class 命令聲明的全局變量,不屬於頂層對象的屬性,window 沒法訪問到。var 命令和 function 命令聲明的全局變量,屬於頂層對象的屬性,window 能訪問到。

因此 狀況 1 中改成:

let name = 'xiaoming'
function foo () {
  console.log(this.name)
}
foo() // undefined

🚀 參考

相關文章
相關標籤/搜索