這一節不涉及具體設計模式,只是針對我們後續的學習做一個鋪墊,如果是對這三者很瞭解的話請跳過此節。
JavaScript 的 this 總是指向一個對象,具體指向哪個對象在運行時基於函數的執行環境動態綁定的,而非函數聲明時的環境。
除去不常用的 with 和 eval 的情況,this 的指向大致分爲以下4種:
- 作爲對象的方法調用
- 作爲普通函數調用
- 構造器調用
- Function.prototype.call 或 Function.prototype.apply 調用
1、作爲對象方法調用
如果對象的方法裏面包含this
,this
指向的就是方法運行時所在的對象。該方法賦值給另外一個對象,就會改變this
的指向。
let obj = {
a:1,
getA:()=>{
alert(this === obj) //輸出:true
alert(this.a) //輸出: 1
}
}
obj.getA()
2、作爲普通函數調用
全局環境使用 this
,它指的就是頂層對象 window
。
window.name = "globalName"
let getName = ()=>{
return this.name
}
console.log(getName()) //輸出: globalName
// 再來看這一個
let obj = {
name:'seven',
getCurName:()=>{
return this.name
}
}
let getOtherName = obj.getCurName
console.log(getOtherName()) //輸出:globalName
上面第二個例子是不是困惑了,哈哈。再去好好讀讀本篇文章的第二段話,多讀幾遍,加深理解,函數getOtherName
在 console.log 裏面執行時所處的執行環境此時是在全局作用域內,所以 this 的指向是 window。
3、作爲構造器調用
構造函數的 this
,指向實例對象。
let obj = (p)=>{
this.p = p
}
let o = new obj('love')
console.log(o.p) //輸出:love
4、Function.prototype.call 或 Function.prototype.apply 調用
跟普通函數調用相比,這兩個調用可以動態改變傳入函數的this
。
let obj1 = {
name:'seven',
getName: ()=>{
return this.name
}
}
let obj2 = {
name:'anne'
}
console.log(obj1.getName()) //輸出:seven
console.log(obj1.getName.call(obj2)) //輸出:anne
擴展一下:
綁定this
的方法
也就是常用的call
, apply
, bind
三個方法。
三者都可以接受多個參數;但是第一個參數是this
所要指向的那個對象。區別如下:
call
,apply
,bind
三者第一個參數都是 this 要指向的對象,也就是想指定的上下文;call
,apply
,bind
三者都可以利用後續參數傳參;bind
是返回對應 函數,便於稍後調用;call
,apply
則是立即調用 。- 對於
call
,apply
二者而言,作用完全一樣,只是接受 參數 的方式不太一樣。call
是把參數按順序傳遞進去,而apply
則是把參數放在數組 裏。
注意點:
- 方法的參數,應該是一個對象。如果參數爲空、null和undefined,則默認傳入全局對象。
- 如果方法的第一個參數是一個原始值,那麼這個原始值會自動轉成對應的包裝對象,然後傳入方法。