this指向、call、apply、bind

思考下面这几种情况下输出的结果,来理解this的指向问题

var name = 'windowName'
function a(){
    var name = 'zhangsan'
    console.log(this.name)
}
a()

解释:
this 指向的是调用他的对象,上面的 a() 是没有调用者的,所以 this 指向的是默认的 windowvar name = 'windowName' 就是先把 name 属性挂到 window 上,然后再赋值为 windowName

var name = 'windowName'
var a = {
    name: 'zhangsan',
    fn: function(){
        console.log(this.name)
    }
}
a.fn()

解释:
fn() 的调用者是 a ,所以 this 指向 athis.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 对象呢?

  1. 可以使用箭头函数
setTimeout(() => {
  this.func1()
},100)
  1. 可以用一个变量存储指针
var that = this
setTimeout(function(){
  that.func1()
},100)
  1. 使用 函数.call(作用域对象)
setTimeout(function(){
  this.func1()
}.call(a),100)
  1. 使用函数.apply(作用域对象)
setTimeout(function(){
  this.func1()
}.apply(a),100)

可以看到 callapply 都可以改变 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)
  1. 使用 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
}

你可能感兴趣的:(this指向、call、apply、bind)