• 81. this、call、apply、bind?


    81. this、call、apply、bind?

    对 this 对象的理解

    this执行上下文中的一个属性, 它指向最后一次调用这个方法的对象。在实际开发中, this 的指向可以通过四种调用模式来判断。

    • 第一种是函数调用模式, 当一个函数不是一个对象的属性时, 直接作为函数来调用时, this 指向全局对象
    • 第二种是方法调用模式, 如果一个函数作为一个对象的方法来调用时, this 指向这个对象
    • 第三种是构造器调用模式, 如果一个函数用 new 调用时, 函数执行前会新创建一个对象, this 指向这个新创建的对象
    • 第四种是 applycallbind 调用模式, 这三个方法都可以显示的指定调用函数的 this 指向
      • apply 方法接收两个参数: 一个是 this 绑定的对象, 一个是参数数组
      • call 方法接收的参数: 一个是 this 绑定的对象, 后面的其余参数是传入函数执行的参数。也就是说, 在使用 call() 方法时, 传递给函数的参数必须逐个列举出来
      • bind 方法通过传入一个对象, 返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变, 其他情况下都不会改变

    这四种方式, 使用构造器调用模式的优先级最高, 然后是 applycallbind 调用模式, 然后是方法调用模式, 然后是函数调用模式。

    call() 和 apply() 的区别?

    它们的作用一模一样, 区别仅在于传入参数的形式的不同。

    • apply 接受两个参数, 第一个参数指定了函数体内 this 对象的指向, 第二个参数为一个带下标的集合, 这个集合可以为数组, 也可以为类数组, apply 方法把这个集合中的元素作为参数传递给被调用的函数
    • call 传入的参数数量不固定, 跟 apply 相同的是, 第一个参数也是代表函数体内的 this 指向, 从第二个参数开始往后, 每个参数被依次传入函数

    实现call、apply 及 bind 函数

    call 函数的实现步骤

    • 判断调用对象是否为函数, 即使是定义在函数的原型上的, 但是可能出现使用 call 等方式调用的情况
    • 判断传入上下文对象是否存在, 如果不存在, 则设置为 window
    • 处理传入的参数, 截取第一个参数后的所有参数
    • 将函数作为上下文对象的一个属性
    • 使用上下文对象来调用这个方法, 并保存返回结果
    • 删除刚才新增的属性
    • 返回结果
    Function.prototype.myCall = function (context) {
        // 判断调用对象
        if (typeof this !== "function") {
            console.error("type error");
        }
        // 获取参数
        let args = [...arguments].slice(1),
            result = null;
        // 判断 context 是否传入, 如果未传入则设置为 window
        context = context || window;
        // 将调用函数设为对象的方法
        context.fn = this;
        // 调用函数
        result = context.fn(...args);
        // 将属性删除
        delete context.fn;
        return result;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    apply 函数的实现步骤

    • 判断调用对象是否为函数, 即使是定义在函数的原型上的, 但是可能出现使用 call 等方式调用的情况
    • 判断传入上下文对象是否存在, 如果不存在, 则设置为 window
    • 将函数作为上下文对象的一个属性
    • 判断参数值是否传入
    • 使用上下文对象来调用这个方法, 并保存返回结果
    • 删除刚才新增的属性
    • 返回结果
    Function.prototype.myApply = function (context) {
        // 判断调用对象是否为函数
        if (typeof this !== "function") {
            throw new TypeError("Error");
        }
        let result = null;
        // 判断 context 是否存在, 如果未传入则为 window
        context = context || window;
        // 将函数设为对象的方法
        context.fn = this;
        // 调用方法
        if (arguments[1]) {
            result = context.fn(...arguments[1]);
        } else {
            result = context.fn();
        }
        // 将属性删除
        delete context.fn;
        return result;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    bind 函数的实现步骤

    • 判断调用对象是否为函数, 即使是定义在函数的原型上的, 但是可能出现使用 call 等方式调用的情况
    • 保存当前函数的引用, 获取其余传入参数值
    • 创建一个函数返回
    • 函数内部使用 apply 来绑定函数调用, 需要判断函数作为构造函数的情况, 这个时候需要传入当前函数的 thisapply 调用, 其余情况都传入指定的上下文对象
    Function.prototype.myBind = function (context) {
        // 判断调用对象是否为函数
        if (typeof this !== "function") {
            throw new TypeError("Error");
        }
        // 获取参数
        var args = [...arguments].slice(1),
            fn = this;
        return function Fn() {
            // 根据调用方式, 传入不同绑定值
            return fn.apply(
                this instanceof Fn ? this : context,
                args.concat(...arguments)
            );
        };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    基于PyTorch的flappy bird游戏
    机器学习基础了解
    pmp考试有包过班吗?靠谱吗?
    “一馆一策”保亚运,精准气象服务背后的数据魔法
    数据结构与算法之一道题感受算法(算法入门)
    适用于初学者的 .NET MAUI
    Pyside6 安装和简单界面开发
    JAVA基础(JAVA SE)学习笔记(二)变量与运算符
    某大学作业
    黄素单核苷酸小麦麦清白蛋白纳米粒|石杉碱甲乳清白蛋白纳米粒Huperzine-whey protein|化学试剂
  • 原文地址:https://blog.csdn.net/m0_51180924/article/details/126775979