改this指向的原理和手写原理

87 阅读1分钟

码万行代码不如懂其原理,问题千变万化,答案也随着问题变化而变化,但是你掌握套路(原理),所有的变化都是鸿毛;

call和apply

  • 相同点

    • 改变this指向
    • 首个传参都是要指向的对象
      • Function.call(target,one,two...)
      • Function.apply(target,Array)
    • 立即执行
  • 不同点

    • 传参方式
      • call一个个的传入
      • apply传入一个数组
  • 例子

var user = { name:'louiebb' }
var sayHello = function(...args){
   console.log(this.name+' say hello world!',args)
}
sayHello.call(user,1,2,3)
sayHello.apply(user,[1,2,3])
  • 例子剖析
    • 上述call和apply可以翻译装饰器模式:成给user新增函数,执行函数,删除函数
      • user.fn = sayHello
      • user.fn()
      • delete user.fn 备注:装饰器模式自行百度
  • 源码
Function.prototype.MyCall = function(context, ...args) {
    context = context || window // 默认指向window
    context.fn = this // this代表函数
    context.fn(...args) // 执行改该函数并通过es6扩展字符拆分数组
    delete context.fn
}

Function.prototype.MyApply = function(context, ...args) {
    context = context || window
    context.fn = this
    context.fn(args) // apply传递数组
    delete context.fn
}

bind

  • 特点:
    • 传参与call的一致
    • 返回一个改变this的捆绑this函数
      • 即使用bind返回的函数再用三大函数改this是无法更改,因为改函数捆绑了this
  • 例子
var user = { name:'louiebb' }
var sayHello = function(...args){
   console.log(this.name+' say hello world!',args)
}
let temp = sayHello.bind(user,1,2,3)
temp(4,5,6)
  • 例子剖析
    • bind通过闭包的特点,内部函数(即返回的函数)访问外部函数的变量,使得1,2,3和4,5,6合并
  • 源码
Function.prototype.myBind = function (context, ...args) {
    var fn = this;//即当前函数sayHello属于函数,会通过原型寻找到myBind
    var temArgs = args
    return function(...crArgs) {
        // 内部访问外部变量temArgs
        return fn.apply(context,temArgs.concat(crArgs))
    }
}