call/apply/bind 实现

165 阅读1分钟

Function.prototype.call

func.call(thisArg, arg1, arg2,...)

运行func, 将提供的第一个参数thisArg作为this,后面的作为函数的参数

例如:

function func(){
    console.log(this.message)
}
// 这个怎么样

var o = {
    message: 'call func practice'
}

func.call(o) // call func practice

So, call主要实现的功能:

  1. 改变this的指向
  2. 执行函数

模拟实现

模拟实现 call 一共分为三步:

  • 将函数设置为对象的属性
  • 执行函数
  • 删除对象的这个属性
Function.prototype.call = function(context) {
    // 非严格模式下 指定为 null 和 undefined 的this值会自动指向全局对象
    // 值为原始值的this会指向该原始值的自动包装对象
    context = context ? Object(context) : window
    context.fn = this // this就是调用call的函数 利用context对象调用fn函数 fn内部的this指向的就是context
    
    // 执行该函数
    let args = [...arguments].slice(1)
    let result = context.fn(...args)
    
    delete context.fn
    return result
}

Function.prototype.apply

apply 方法调用一个具有给定this值的函数,以及作为一个数组(或类数组对象)提供的参数

func.apply(thisArg,[argsArray])

它运行 func 设置 this=context 并使用类数组对象 args 作为参数列表

call 和 apply 之间唯一的语法区别是 call 接受一个参数列表,而 apply 则接受带有一个类数组对象

模拟实现apply

Function.prototype.apply = function(context, arr) {
    context = context ? Object(context): window
    context.fn = this
    
    let result
    if(!arr) {
        result = context.fn()
    }else {
        result = context.fn(...arr)
    }
    
    delete context.fn
    return result
}

Function.prototype.bind

实现步骤:

  • 传入参数:调用绑定函数时作为this传递给目标函数,添加到绑定函数参数列表中的参数
  • 返回值:返回一个原函数的拷贝,并拥有指定的this值和初始参数
Function.prototype.bind = function(context) {
    context = context ? Object(context) : window
    var self = this // 函数副本
    // 获取其余参数
    var args = [].slice.call(arguments,1)
    // 返回一个原函数的拷贝,并且拥有指定this和初始参数
    return function() {
        self.apply(context, args.concat([].slice.call(arguments)))
    }
}