思考下面這幾種情況下輸出的結(jié)果,來理解this的指向問題
var name = 'windowName'
function a(){
var name = 'zhangsan'
console.log(this.name)
}
a()
解釋:
this 指向的是調(diào)用他的對象,上面的 a() 是沒有調(diào)用者的,所以 this 指向的是默認的 window,var name = 'windowName' 就是先把 name 屬性掛到 window 上,然后再賦值為 windowName
var name = 'windowName'
var a = {
name: 'zhangsan',
fn: function(){
console.log(this.name)
}
}
a.fn()
解釋:
fn() 的調(diào)用者是 a ,所以 this 指向 a ,this.name 也就是 a.name
var name = 'windowName'
var a = {
name: 'zhangsan',
fn: function(){
console.log(this.name)
}
}
var f = a.fn
f()
解釋:
fn() 沒有調(diào)用者,所以 this 指向的是默認的 window ,所以打印的是 windowName
var name = 'windowName'
function fn(){
var name = 'zhangsan'
innerFun()
function innerFun(){
console.log(this.name)
}
}
fn()
解析:
同理,fn() 并沒有調(diào)用者,所以 this 指向的還是 window
var name = 'windowName'
var a = {
name: 'zhangsan',
func1: function(){
console.log(this.name)
},
func2: function(){
setTimeout(function(){
this.func1()
},100)
}
}
a.func2()
解析:
在這里,setTimeout 中的 this 沒有調(diào)用者,所以指向的是 window ,所以結(jié)果是 undefined
那如何才能使這里的 setTimeout 中的這個 this 指向 a 對象呢?
- 可以使用箭頭函數(shù)
setTimeout(() => {
this.func1()
},100)
- 可以用一個變量存儲指針
var that = this
setTimeout(function(){
that.func1()
},100)
- 使用
函數(shù).call(作用域?qū)ο?
setTimeout(function(){
this.func1()
}.call(a),100)
- 使用
函數(shù).apply(作用域?qū)ο?
setTimeout(function(){
this.func1()
}.apply(a),100)
可以看到 call 和 apply 都可以改變 this 的指向,但是他們有什么區(qū)別呢?
var a = {
name: 'zhangsan',
fn: function(a,b){
console.log(a + b)
}
}
var b = a.fn
// 多個參數(shù)是用數(shù)組的形式傳遞
b.apply(a, [1,2])
// 多個參數(shù)直接在后面追加傳遞
a.call(a,1,2)
- 使用
bind綁定作用域,但不立即執(zhí)行,需要手動再執(zhí)行
setTimeout(function(){
this.func1()
}.bind(a)(),100)
call的實現(xiàn)原理
Function.prototype.mycall = function(ctx){
ctx = ctx || window
ctx.fn = this // 這個this就是調(diào)用者對象
let arg = [...arguments].slice(1)
let result = ctx.fn(...arg)
return result
}