zoukankan      html  css  js  c++  java
  • 模拟实现js的new

    new是什么

    一句话介绍newnew运算符创建一个用户自定义的对象类型的实例,或者具有构造函数的内置对象类型之一。看下下面的代码来了解new操作符都做了什么事情

    // Class (constructor)
    function Person(name,age){
        this.name = name
        this.age = age
        this.habit = 'watch tv'
    }
    
    // 每个函数都有prototype对象属性
    // 在类的原型上挂载属性和方法,挂载载原型上,每个实例都可以调用,并且不会每个实例都挂载相同的属性和方法
    Person.prototype.strLength = 60
    Person.prototype.sayName = function(){
        console.log('I am '+ this.name)
    }
    
    // 实例化对象
    const person = new Person("yato", 50)
    person.sayName();
    console.log(person)
    
    

    进一步理解new

    从上面这个例子中,我们可以看到,实例person可以

    • 访问到Person构造函数里的属性
    • 访问到Person.prototype中的属性

    接下来模拟实现一个类似new的newFake,使用方式如下

    function Person(arguments){
        // ...
    }
    
    // 使用new
    let person = new Person(arguments)
    
    // 使用newFake
    let person = newFake(Person,arguments)
    

    初步实现

    function newFake(){
        let obj = Object.create({})
    
        let Constructor = [].shift.call(arguments)
    
        if(typeof Constructor !== 'function'){
            throw 'newOperator function the first param must be a function';
        }
            
        // 将新建对象的[[prototype]]属性指向到构造函数的prototype属性
        obj.__proto__ = Constructor.prototype
    
        // 修改this指向到obj
        Constructor.apply(obj, arguments)
    
        return obj
    }
    
    function Person(name,age){
        this.name = name
        this.age = age
        this.habit = 'watch tv'
    }
    
    // 每个函数都有prototype对象属性
    // 在类的原型上挂载属性和方法,挂载载原型上,每个实例都可以调用,并且不会每个实例都挂载相同的属性和方法
    Person.prototype.strLength = 60
    Person.prototype.sayName = function(){
        console.log('I am '+ this.name)
    }
    
    // 实例化对象
    const person = newFake(Person,"yato", 50)
    person.sayName();  // I am yato
    console.log(person)  // Person { name: 'yato', age: 50, habit: 'watch tv' }
    

    返回值处理

    如果构造函数有返回值的情况

    function Person(name,age){
        this.strLength = 60
        this.age = age
        
        return {
     	name: name,
            habit: 'game'
        }
    }
    
    let person = new Person('yato', 18)
    
    console.log(person.name) // yato
    console.log(person.habit) // game
    console.log(person.strength) // undefined
    console.log(person.age) // undefined
    

    在这个例子中,构造函数返回了一个对象,在实例person中只能访问返回对象中的属性,而且还要注意一点,这里我们是返回一个对象,假设我们只返回一个基本类型值呢,看下面的例子

    function Person(name,age){
        this.strLength = 60
        this.age = age
        
        return 'good job'
    }
    
    let person = new Person('yato', 18)
    
    console.log(person.name) // undefined
    console.log(person.habit) // undefined
    console.log(person.strength) // 60
    console.log(person.age) // 18
    

    结果和正常new实例,无返回值的时候表现是一样的!可以得出结论:new操作最后一步,需要判断一返回值是否是一个对象,如果是一个对象就返回这个对象,如果不是对象就返回我们new内部的实例对象

    第二版的new实现

    function newFake(){
        let obj = Object.create({})
    
        let Constructor = [].shift.call(arguments)
    
        if(typeof Constructor !== 'function'){
            throw 'newOperator function the first param must be a function';
        }
        
        // ES6 new.target 是指向构造函数
        newFake.target = Constructor;
            
        // 将新建对象的[[prototype]]属性指向到构造函数的prototype属性
        obj.__proto__ = Constructor.prototype
    
        // 修改this指向到obj
        let ret = Constructor.apply(obj, arguments)
        
        // 判断返回值是否为对象 Object(包含Functoin, Array, Date, RegExg, Error)都会直接返回这些值。
        // 这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除	 // null
        let isObject = typeof ret === 'object' && ret !== null;
        let isFunction = typeof ret === 'function';
    
        if(isObject || isFunction){
            return ret;
        }
        
        return obj
    }
    

    总结一下new做了什么

    • 创建了一个全新的对象
    • 这个对象会被执行实例[[prototype]]属性Classprototype对象属性的链接(原型链)
    • 生成的新对象会成为构造函数的调用的this(修改this指向)
    • 通过new创建的每个实例对象最终将被[[prototype]]链接到构造函数的prototype对象上
    • 如果函数没有返回对象类型(包含Function, Array,Date,RegExg,Error),那么new表达式中的函数会自动返回这个新的对象
  • 相关阅读:
    Java 21-Spring知识
    Java18-黑马旅游网学习制作
    Java17-Filter&Listener&Json&redis&maven
    python发邮件
    一元模型拟合(OLS和插值np拟合)
    一元模型拟合
    2.13 描述性统计(平均数,中位数,中数,数据的离散度(极差,平均绝对偏差,方差标准差))
    tushare 股票数据获取,收益率计算,直方图绘制
    主板指数数据的爬取(selenium处理JS)
    网页整页截图小工具
  • 原文地址:https://www.cnblogs.com/qiqiloved/p/13475521.html
Copyright © 2011-2022 走看看