JS 中的 this 對每位前端工程師都不陌生,常常看到對象這裏 this 那裏 this,那什麼是 this?答案就是上下文對象,即被調用函數所處的環境,也就是說,this 在函數內部指向了調用函數的對象。前端
通俗的講,就是誰調用了函數。es6
this 指向 window數組
var name = 'xiaoming' // 思考,爲何不能用 let 或者 const ? function foo () { console.log(this.name) } foo() // xiaoming
誰調用了這個函數,答案就是 window。這好理解,由於這裏的變量和函數都是直接掛在 window 上的,等同於 window.foo()。需注意,嚴格模式下,this 爲 undefined
前端工程師
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
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 來調用函數,或者說發生構造函數調用時,會自動執行下面的操做:
這個例子中,使用 new 來調用 Person(..) 時,咱們會構造一個新對象(jser)並把它綁定到 Person(..) 調用中的 this 上。
或者能夠這麼想,誰調用了 getName ?就是 jser 調用了,因此 this 指向了 jser
用 call,apply 和 bind 來修改 this 指向
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 能夠永久性的修改函數中的 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 都不能被修改
若是你把 null 或者 undefined 做爲 this 的綁定對象傳入 call、apply 或者 bind,這些值再調用時會被忽略,實際應用的是默認綁定。
ES6 中介紹了一種沒法使用這些規則的特殊函數類型:箭頭函數,根據外層(函數或者全局)做用域來決定 this,箭頭函數經常使用於回調函數
ES6 中,let 命令、const 命令、class 命令聲明的全局變量,不屬於頂層對象的屬性,window 沒法訪問到。var 命令和 function 命令聲明的全局變量,屬於頂層對象的屬性,window 能訪問到。
因此 狀況 1 中改成:
let name = 'xiaoming' function foo () { console.log(this.name) } foo() // undefined