手写call、apply、bind

概要

本章主要记录一下手写call 、 apply、 bind 函数的思路

一、call()

在使用一个指定的this和若干个指定的参数值的前提下调用某个函数或方法

示例:
    let foo = {
        value: 1
    };
    function bar() {
        console.log(this.value)
    }
    bar.call(foo); // 1

在以上例子中,我们能确定两点:1. call改变了this的指向,指向到foo;2.bar 函数执行了;
那call() 函数执行的原理是什么呢?

思路:
  1. 判断执行对象是否为函数
  2. 获取执行函数的参数
  3. 传入值判断,是否有值,如果没有,默认为全局 即 window
  4. 执行对象挂载在上下文之上
  5. 在上下文中调用执行对象并且传入执行参数
  6. 将上下文复原,删除新增临时属性
  7. 返回5 的结果
代码实现:
	//输入 : 上下文 执行函数的参数
    //输出 : 执行结果
    const myCall = function (context){
        //1. 判断执行对象是否为函数
        if(typeof this !== 'function') {
            console.error('this is not a function')
        }
        //2. 获取执行函数的参数
        let args = [...arguments].slice(1),
            result = null;
        //3. 传入值判断,是否有值,如果没有,默认为全局 即window
        if(!context){
            context  = window;
        }
        // 4. 执行对象挂载在上下文之上
        context.fn = this;
        // 5. 在上下文中调用执行对象并且传入执行参数
        result = context.fn(...args);
        // 6. 将上下文复原,删除新增临时属性
        delete context.fn
        // 7. 返回5的结果
        return result; 
    }

二、apply()

apply 和 call 执行思路一致,但是入参不一样。apply 入参是数组。

代码实现
const myApply = function(context) {
    // 1. 判断执行对象是否为函数
    if (typeof this !== 'function') {
        console.error('this is not a function');
    }
    // 2. 获取执行函数的参数
    let args = arguments[1],
        result = null;

    // 3. 传入值判断,是否有值,如果没有,默认为全局即window
    if (!context) {
        context = window;
    }
    // 4. 执行对象挂载在上下文之上
    context.fn = this;
    // 5. 在上下文中调用执行对象并且传入执行参数
    if (args) {
        result = context.fn(...args);
    } else {
        result = context.fn();
    }
    // 6. 将上下文复原,删除新增临时属性
    delete context.fn;
    // 7. 返回5的结果
    return result;
}

三、bind()

bind() 传参一致,但是返回的是待执行的函数

	const myBind = function (context) {
      // 1. 判断执行对象是否为函数
        if (typeof this !== 'function') {
            console.error('this is not a function')
        }
        // 2. 获取参数
        let args = [...arguments].slice(1),
            fn = this;
        return function Fn() {
            // 3. 根据调用方,确定最终返回值
            return fn.apply(
                this instanceof Fn ? this : context,
                args.concat(...arguments)
            )
        }
        
    }

小结

三者对比

共同点:
  1. 都是用来改变函数的执行上下文(this 指向)。
  2. 都可以传递参数给函数。
  3. 都是函数的原型方法,可以在任何函数上使用。
区别:
  1. 参数传递方式

    • callapply 都可以传递参数给函数,但是它们的参数传递方式不同。call 方法接受一系列参数,直接作为函数的参数传入;apply 方法接受一个数组,将数组元素作为函数的参数传入。
    • bind 方法创建一个新函数,传递给 bind 的参数会被作为绑定函数的前置参数,调用绑定函数时再加上调用时的参数。
  2. 立即执行 vs 延迟执行

    • callapply 方法会立即执行函数,并返回函数的执行结果。
    • bind 方法创建一个新函数,需要显式调用才会执行。
  3. 返回值

    • callapply 方法直接执行函数并返回函数的执行结果。
    • bind 方法返回一个新函数,不会立即执行,需要在之后调用。
  4. 改变函数执行上下文的方式

    • call 方法接受一个上下文对象和一系列参数,将函数的执行上下文指向该对象。
    • apply 方法同样接受一个上下文对象和参数数组,也将函数的执行上下文指向该对象。
    • bind 方法接受一个上下文对象,返回一个新函数,新函数的执行上下文会被永久绑定到上下文对象。
  5. 使用场景

    • callapply 更适合在已知参数数量时使用,如将一个对象方法应用于另一个对象。
    • bind 更适合在预先设定一部分参数,以后再调用函数时使用,例如创建事件处理程序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值