介紹
this 是一個(gè)對(duì)象,指向函數(shù)的執(zhí)行上下文或執(zhí)行環(huán)境鹊杖。
正常情況下是動(dòng)態(tài)綁定悴灵。
動(dòng)態(tài)綁定的意思是只有程序運(yùn)行時(shí)才會(huì)確定最終指向。
但箭頭函數(shù)和強(qiáng)制綁定例外骂蓖。
默認(rèn)綁定
function fn(){
console.log(this)
}
// window
隱式綁定
var obj = {
a: 1,
fn: function () {
console.log(this)
}
}
obj.fn() // obj
var fn1 = obj.fn
fn1() // window
因?yàn)閠his是動(dòng)態(tài)綁定的积瞒,而fn1 和 obj.fn 均是引用地址,實(shí)際情況還是得程序運(yùn)行時(shí)去確定this的指向登下。
顯示綁定
我們可以通過(guò)call,apply,bind方法來(lái)強(qiáng)制改變this指向茫孔。
var obj = {
a: 1,
fn: function(){
console.log(this)
},
fn2: () => {
console.log(this)
},
fn3: {
fn: () => {
console.log(this)
}
},
fn4: function () {
console.log(1, this)
return () => {
console.log(2, this)
}
}
}
var person = {
name: 'zs'
}
obj.fn() // obj
obj.fn2() // window
obj.fn.call(person) // person 1
obj.fn2.call(person) // window 2
obj.fn3.fn() // window 3
obj.fn4()() // 1:obj 2:obj 4
1: 使用call,apply,bind 強(qiáng)制改變this指向;
2: 箭頭函數(shù)內(nèi)的this無(wú)法被改變被芳;
4: 箭頭函數(shù)不會(huì)創(chuàng)建自己的this,它只會(huì)從自己的作用域鏈的上一層繼承this(箭頭函數(shù)內(nèi)的this指向定義箭頭函數(shù)時(shí)的this)
3: js只有函數(shù)作用域和全局作用域缰贝,沒(méi)有塊級(jí)作用域,因此它的上一級(jí)是全局作用域。
箭頭函數(shù)
箭頭函數(shù)的this指向在上一個(gè)例子中已經(jīng)說(shuō)明了畔濒,這里在概括一下:
1.箭頭函數(shù)不會(huì)創(chuàng)建自己的this,它只會(huì)從自己的作用域鏈的上一層繼承this;
2.箭頭函數(shù)里的this指向無(wú)法被call,apply,bind改變剩晴;
Oh my god
var fn1 = function () {
console.log(1, this)
}
var fn2 = () => {
console.log(2, this)
}
var arr = [fn1, fn2]
for(var i=0;i<arr.length;i++){
arr[i]() // ???
}
output: 1 arr // WTF ???
2 window
從這個(gè)例子中可以看到如果通過(guò)下標(biāo)的方式去訪問(wèn)數(shù)組中的對(duì)象,會(huì)將this綁定到數(shù)組這個(gè)對(duì)象,由此帶來(lái)的安全問(wèn)題難以想象(發(fā)布訂閱模式中)
For example:
function subpub() {
var subscribtions = []
function subscribe(subscriber){
subscribtions.push(subscriber)
}
function publish(){
for(var i=0;i<subscribtions.length;i++){
subscribtions[i]()
}
}
return {
subscribe,
publish
}
}
var subpubInstance = subpub()
subpubInstance.subscribe(function(){
console.log(1, this)
this.length = 0 // 搞破壞
})
subpubInstance.subscribe(function(){
console.log('dooooo')
})
subpubInstance.publish() // oh shit
How to fix it?
// 不要通過(guò)下標(biāo)的形式去獲取
function publish(){
// for(var i=0;i<subscribtions.length;i++){
// subscribtions[i]()
// }
subscribtions.forEach(fn => {
fn()
})
}