zoukankan      html  css  js  c++  java
  • 同学给我来个手写的new吧

    1.手写一个new

    首先看看new怎么用

    function Person(name){
        this.name = name
    }
    Person.prototype.eat = function() {
        console.log("Eating")
    }
    var qd = new Person('qd')
    console.log(qd)
    qd.eat();
    
      使用new创建的实例:
        能够访问构造函数里的属性(name);
        能够访问原型中的属性(eat)
    
    在调用new时候发生了四件事:
        1新生成一个对象
        2将构造函数的作用域赋值给新对象(即绑定新对象的 this)
        3执行构造函数中的代码(即为这个新对象添加属性)
        4返回新对象
    

    A版本

    function create() {
        //1.获取构造函数,并删除arguments中的第一项
        var Con = [].shift.call(arguments);
        
        //2.创建一个空对象并连接到构造函数的原型,使它能够访问原型中的属性
        var obj = Object.create(Con.prototype);
        
        3.使用apply改变构造函数中this的指向实现继承,使obj能够访问到构造函数中的属性
        var ret = Con.apply(obj,arguments);
        
        4.优先返回构造函数返回的对象
        return ret instanceof Object ? ret : obj;
    }
    

    解释一下4中的判断:主要考虑的是没有返回值,

    //1.有返回值且为对象:
    function Person (name, sex) {
        this.name = name
        return {
            sex:sex
        }
    }
    1.构造函数中有返回值且为对象,那么创建的实例就只能访问到返回对象中的属性,
    所以要判断一下ret的类型,如果是对象的话,则返回这个对象。
    
    //2构造函数没有返回值:
    function Person(name){
        this.name = name;
    }
    2.构造函数没有返回值,那么创建的实例就能访问这个构造函数中的所有属性了,此时ret就会为undefined,所以返回obj。
    
    3,返回值为基本类型
    function Person(name){
        this.name = name
        return 'str'
    }
    3.构造函数中没有返回值但是返回值是undefined以外的其他基本类型(比如字符串),这种情况当成第二种情况(没有返回值)来处理。
    

    好了我们来验证一下吧:

    function Person (name) {
        this.name = name
    }
    Person.prototype.eat = function() {
        console.log("Eating")
    }
    
    function create() {
        var Con = [].shift.call(arguments);
        var obj = Object.create(Con.prototype);
        var ret = Con.apply(obj, arguments);
        return ret instanceof Object ? ret : obj;
    }
    
    //调用
    var qdleader = create(Person, 'qdleader');
    console.log(qdleader); //Person{name:'LinDaiDai'}
    qdleader.eat()  //'Eatting'
    
    
    
    
    
    

    注意:object.create方法,参数为new出来的实例的原型,也就是_proto_的指向

    还有其他版本的: b版本

    function create() {
        // 创建一个空的对象
        let obj = {}
        // 获得构造函数
        // 因为 arguments 类数组,所以我们可以用数组的 shift 来实现 arguments 的 ‘push’ 和 ‘pop’
        // 将 arguments 进数组,并将第一个元素移除并赋值给 Con (Constructor).
        let Con = [].shift.call(arguments)
        // 链接到原型
        obj.__proto__ = Con.prototype
        // 绑定this,并执行构造函数,就相当于 obj .constructor(arguments)
        let result = Con.apply(obj, arguments)
        // 确保 new 出来的是个对象
        return typeof result === 'object' ? result : obj
    }
    
    
    
    
    1:arguments是一个类数组,以像是数组的样子取到传入的所有参数,有一个callee属性(值为被调用的方法)利用数组的shift方法拿到了第一项 也就是Animal函数,同时原来的arguments被更改,失去了第一个参数。再后面被apply拿来做参数
    
    2:Constructor.apply(obj, arguments)
    意思是在obj里执行构造函数,并且挨着arguments里剩下的参数
    
    3:[ ]可以等价Array.prototype.shift ,也就是在arguments上执行数组的shift方法的意思
    
    4:最后可以加一个判断,是否为对象再返回
    

    比b版本更好一点的写法:

    function _new() {
        let target = {}; //创建的新对象
        //第一个参数是构造函数
        let [constructor, ...args] = [...arguments];
        //执行[[原型]]连接;target 是 constructor 的实例
        target.__proto__ = constructor.prototype;
        //执行构造函数,将属性或方法添加到创建的空对象上
        let result = constructor.apply(target, args);
        if (result && (typeof (result) == "object" || typeof (result) == "function")) {
            //如果构造函数执行的结构返回的是一个对象,那么返回这个对象
            return result;
        }
        //如果构造函数返回的不是一个对象,返回创建的新对象
        return target;
    }
    

    个人感觉A版本好一些

    欢迎加群!

  • 相关阅读:
    洛谷 P2421 [NOI2002]荒岛野人
    POJ 2115 C Looooops
    POJ 3292 Semi-prime H-numbers
    [网络流24题]负载平衡问题(费用流)
    [网络流24题]骑士共存问题
    POJ 3281 Dining
    洛谷 1306斐波那契公约数
    ELK+Filebeat 安装配置入门
    一个JS内存泄露实例分析
    Node.js 事件循环
  • 原文地址:https://www.cnblogs.com/bbqq1314/p/12545583.html
Copyright © 2011-2022 走看看