• JS重写内置 call 方法


    看一下.call都做了些什么

    let obj = {
      age: 18
    }
    function fn(...params) {
      console.log(this.age, ...params);// 18 "参数1" "参数2" "参数n"
      return "返回值"
    }
    console.log(fn.call(obj, "参数1", "参数2", "参数n"))// "返回值"
    
    1. this指向了.call()的第一个参数。2. 从第二个参数到最后一个参数,会对 fn 进行传参。3. 执行函数 fn

    模拟 call 方法,写一个 myCall 方法

    let obj = {
      age: 18
    }
    function fn(...params) {
      console.log(this.age, ...params)
    }
    Function.prototype.myCall = function myCall(context, ...params) {
      // 此时的 myCall 还仅仅是个函数,不能做任何事
    }
    // 将来要和原来的 call 方法一样使用。
    fn.myCall(obj, "参数1", "参数2", "参数n")
    

    第一步改变this指向

    如果将 fn 变成 obj 的一个属性,并调用obj.fn(),此时 fn 中的 this 自然指向 obj。

    let obj = {
      age: 18
    }
    function fn(...params) {
      console.log(this.age, ...params)
    }
    obj.fn = fn
    obj.fn("参数1", "参数2", "参数n") // 18 "参数1" "参数2" "参数n"
    

    所以,myCall 中可以这样写:

    let obj = {
      age: 18
    }
    function fn(...params) {
      console.log(this.age, ...params)
    }
    Function.prototype.myCall = function myCall(context, ...params) {
      let fn = Symbol();
      context[fn] = this; // 这里的 this 是.前面的主,即 fn,我们将 fn 当做一个属性赋值给 context
      context[fn](); // 执行 context.fn(),之后 fn 中的 this,自然指向.前面的主,即 context
    }
    fn.myCall(obj, "参数1", "参数2", "参数n") // 18
    

    可以看到,这一步,我们实现了函数 fn 中的 this 指向变为 obj 的功能,并执行了 fn 函数

    第二步传递参数给 fn

    这一步就简单了,我们可以用 arguments 从下标1开始截取需要传递的参数,也可以和上面的例子一样,用...params来获取参数,进行传递

    let obj = {
      age: 18
    }
    function fn(...params) {
      console.log(this.age, ...params)
    }
    Function.prototype.myCall = function myCall(context, ...params) {
      let fn = Symbol();
      context[fn] = this; 
      context[fn](...params); // 传参
    }
    fn.myCall(obj, "参数1", "参数2", "参数n") // 18 "参数1" "参数2" "参数n"
    

    看到这一步,基本的 myCall 方法已经完成80%,还有两个小点要注意:

    1. this 参数可以传 null,当为 null 的时候,视为指向 window
    Function.prototype.call = function call(context, ...params) {
      // 做判断,context 应该为 this 需要指向的对象或者函数
      if (context == null) context = window;
      let type = typeof context;
      if (type !== "object" && type !== "function") {
        // 把传递的原始值类型变为对应的对象类型值
        context = Object(context);
      }
      let fn = Symbol();
      context[fn] = this;
      context[fn](...params);
      delete context[fn]; // 用完记得把新加的属性删除掉,不然会越来越。
    };
    
    1. 函数 fn 是可以有返回值的!
    Function.prototype.call = function call(context, ...params) {
      if (context == null) context = window;
      let type = typeof context;
      if (type !== "object" && type !== "function") {
        context = Object(context);
      }
      let fn = Symbol();
      context[fn] = this;
      let result = context[fn](...params); // 函数执行之后,获取到返回值。
      delete context[fn];
      return result // 将获取到的返回值,返回出去。
    };
    

    一个 模拟 call 方法的 myCall 方法完成。

  • 相关阅读:
    CDH环境搭建及部署
    Window 安装Sqoop 环境
    软件——keil的查找,错误,不能跳转到相应的行
    软件——机器学习与Python,输入输出的用法
    软件——机器学习与Python,聚类,K——means
    软件——机器学习与Python,if __name__ == '__main__':函数
    硬件——STM32,ADC篇
    生活的开始
    硬件——nrf51822第三篇,按键控制小灯
    硬件——nrf51822第二篇,如何设置keil用来下载程序
  • 原文地址:https://www.cnblogs.com/MrZhujl/p/14732214.html
Copyright © 2020-2023  润新知