思考下面这几种情况下输出的结果,来理解this的指向问题
var name = 'windowName'
function a(){
var name = 'zhangsan'
console.log(this.name)
}
a()
解释:
this
指向的是调用他的对象,上面的 a()
是没有调用者的,所以 this
指向的是默认的 window
,var name = 'windowName'
就是先把 name
属性挂到 window
上,然后再赋值为 windowName
var name = 'windowName'
var a = {
name: 'zhangsan',
fn: function(){
console.log(this.name)
}
}
a.fn()
解释:
fn()
的调用者是 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()
没有调用者,所以 this
指向的是默认的 window
,所以打印的是 windowName
var name = 'windowName'
function fn(){
var name = 'zhangsan'
innerFun()
function innerFun(){
console.log(this.name)
}
}
fn()
解析:
同理,fn()
并没有调用者,所以 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
没有调用者,所以指向的是 window
,所以结果是 undefined
那如何才能使这里的 setTimeout
中的这个 this
指向 a
对象呢?
- 可以使用箭头函数
setTimeout(() => {
this.func1()
},100)
- 可以用一个变量存储指针
var that = this
setTimeout(function(){
that.func1()
},100)
- 使用
函数.call(作用域对象)
setTimeout(function(){
this.func1()
}.call(a),100)
- 使用
函数.apply(作用域对象)
setTimeout(function(){
this.func1()
}.apply(a),100)
可以看到 call
和 apply
都可以改变 this
的指向,但是他们有什么区别呢?
var a = {
name: 'zhangsan',
fn: function(a,b){
console.log(a + b)
}
}
var b = a.fn
// 多个参数是用数组的形式传递
b.apply(a, [1,2])
// 多个参数直接在后面追加传递
a.call(a,1,2)
- 使用
bind
绑定作用域,但不立即执行,需要手动再执行
setTimeout(function(){
this.func1()
}.bind(a)(),100)
call的实现原理
Function.prototype.mycall = function(ctx){
ctx = ctx || window
ctx.fn = this // 这个this就是调用者对象
let arg = [...arguments].slice(1)
let result = ctx.fn(...arg)
return result
}