模拟实现new

146 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

前言

new关键字在很多编程语言中都有,js中也不例外,今天就来看看new操作到底是如何实现的,让我们来自己实现一个new操作,在模拟实现之前我们要首先知道new到底干了什么,它有什么特性。

new的特点

我们先来看个例子,如下

function animal(color,species){
            this.color = color
            this.species = species
        }

        animal.prototype.attribute = 'run'

        animal.prototype.sayColor = function(){
            console.log('I am' + this.color)
        }

        let dog = new animal('white','dog')
        console.log(dog.color)
        console.log(dog.species)
        console.log(dog.attribute)
        dog.sayColor()

运行截图如下:

image.png

由此可以看出:

  • new 的实例dog可以访问到构造函数的属性
  • 可以访问到构造函数原型上的属性或方法

我们没办法直接写一个new这种类型的东西,所以只能用一个函数来代替,就叫做myNew()吧,这里myNew的第一个参数就是构造函数,后边的参数是传入构造函数的参数,大致的步骤是:

  • 首先我们要生成一个对象,因为new得到的结果是一个对象
  • 这个对象要可以访问构造函数的属性,这点可以通过实例的__proto__来实现(实例.proto=Constructor.proto)
  • 我们还要改变this的指向,因为new的对象中,this是指向实例的
     function myNew(){
            let obj = new Object()
            Constructor = [].shift.call(arguments)
            obj.__proto__ = Constructor.prototype
            Constructor.apply(obj,arguments)
            return obj
        }

我们在来用上面的例子来试一试

 let dog = myNew(animal,'white','dog')
        console.log(dog.color)
        console.log(dog.species)
        console.log(dog.attribute)
        dog.sayColor()

结果如下

image.png

非常nice,成功了

上面的代码实现了new的基本功能,但new还有一个特性,那就是如果构造函函数有return结果,那实例能访问到的东西就会发生变化了,如题如下

  • 如果构造函数返回的是对象,那实例只能访问构造函数中return的对象中的属性或方法
  • 如果返回的是基本数据类型,那就不用管,和没返回是一样的 基于上面的两点,再来改善一下我们的myNew
 function myNew(){
            let obj = new Object()
            Constructor = [].shift.call(arguments)//拿到构造函数
            obj.__proto__ = Constructor.prototype
            result =  Constructor.apply(obj,arguments)
            return typeof result==='object'? result||obj: obj //防止构造函数返回null的情况
        }

总结

new的模拟实现大概就是这样,其中的重点就是要知道new到底都干了什么事,然后一件件来实现这些事就可以了