• 手写JS的new操作符的功能、手写实现JS中Object类的call函数、apply函数的功能


    探究JavaScript中new对象的过程,call()、apply()方法的实现原理

        function Person(name, age) {
            this.name = name;
            this.age = age;
            console.log("Person...");
        }
    
        // let p = new Person("张三", 18);
        // console.log(p);
    
        /**
         * 【目标1:模拟js中new运算符的功能。传入一个构造函数和可选的构造参数,返回对应的构造实例】
         * js new运算符内部原理:1.创建一个空对象;2.修改构造函数内部的this指向为空对象;3.执行构造函数的代码;4.返回创建的对象
         * (当构造函数内部显式返回基本类型或null时等价于不返回,new操作默认会返回this)
         */
        function MyNew(constructor, ...args) {
            if (!constructor || !constructor.hasOwnProperty("prototype")) {
                throw new TypeError("constructor is not a Constructor");
            }
            let obj = Object.create(constructor.prototype); // 创建空对象{}并绑定对象的原型为参数对象constructor.prototype
            let res = constructor.apply(obj, args);
            if (res != null && (typeof res == "object" || typeof res == "function")) { // typeof null = 'object'
                return res;
            }
    
            return obj;
        }
    
        // console.log(MyNew("string类型", '字符串类型', 3)); // Uncaught TypeError: constructor is not a Constructor
        console.log(MyNew(Person, "李四", 21)); // Person...   Person {name: '李四', age: 21}
        console.log(MyNew(Person, "李四")); // Person...   Person {name: '李四', age: undefined}
        console.log(MyNew(function(){console.log('xxx')})); // xxx   {}
    
        /**********************************************************************/
        /**
         * 【目标2:模拟js中Object类的call方法】
         * call方法原理:1.修改调用者函数内部的this指向为call的第一个参数,默认为window;2.执行函数并返回结果。(参数为可变参数)
         */
        Function.prototype.myCall = function (context) {
            context = context ? Object(context) : window; // 如果调用时没有传参数,则指定执行上下文为window,否则按需转换为Object引用类型
            context._tempFunc = this; // 临时绑定调用者函数
            let args = []; // 收集调用者函数的参数,arguments为伪数组
            for (let i = 1; i < arguments.length; i++) {
                args.push(arguments[i]);
            }
            // let res = this(...args); // (错误写法)独立函数调用,内部this指向window,而非context(不合要求,因为call函数显式绑定this)
            let res = context._tempFunc(...args); // 隐式绑定调用者函数内部的this为context
            delete context._tempFunc; // 释放临时函数
    
            return res;
        };
    
        function testFunc(n1, n2) {
            console.log(this);
            return n1 + n2;
        }
        console.log(testFunc.myCall()); // window  NaN
        console.log(testFunc.myCall("hello", 10, 20));  // String {'hello'}   30
        console.log(testFunc.myCall({ a: 'value a' }, 20, 30)); // {a: 'value a'}   50
    
        /**********************************************************************/
        /**
         * 【目标3:模拟js中Object类的apply方法】
         * apply方法原理:1.修改调用者函数内部的this指向为apply的第一个参数,默认为window;2.执行函数并返回结果。(参数为数组)
         */
        Function.prototype.myApply = function (context, args) {
            context = context ? Object(context) : window; // 如果调用时没有传参数,则指定执行上下文为window,否则按需转换为Object引用类型
            context._tempFunc = this; // 临时绑定调用者函数
            // let res = this(args); // (错误写法)独立函数调用,内部this指向window,而非context(不合要求,因为apply函数显式绑定this)
            let res = context._tempFunc(args); // 隐式绑定调用者函数内部的this为context
            delete context._tempFunc; // 释放临时函数
    
            return res;
        };
    
        function testFunc(n1, n2) {
            console.log(this);
            return n1 + n2;
        }
        console.log(testFunc.myApply()); // window  NaN
        console.log(testFunc.myApply("hello", [10, 20]));  // String {'hello'}   30
        console.log(testFunc.myApply({ a: 'value a' }, [20, 30])); // {a: 'value a'}   50
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    『忘了再学』Shell基础 — 24、Shell正则表达式的使用
    测试域: 流量回放-介绍篇
    php实验室安全系统的设计与实现毕业设计-附源码191610
    世界坐标系、相机坐标系和图像坐标系的转换
    MobTech 秒验常见问题
    依靠双工福禄克测试仪进行MPO电缆认证
    JAVA多线程(MultiThread)的各种用法
    iwebsec靶场 代码执行关卡通关笔记
    简述 Mybatis 的插件运行原理,如何编写⼀个插件
    《数据结构、算法与应用C++语言描述》使用C++语言实现数组栈
  • 原文地址:https://blog.csdn.net/xfwdxt/article/details/134266090