js new一个对象的过程,实现一个简单的new方法

 

对于大部分前端开发者而言,new一个构造函数或类获得对应实例,是很是广泛的操做了。下面的例子中分别经过构造函数与class类实现了一个简单的建立实例的过程。html

// ES5构造函数
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
const child = new Parent('听风是风', 26);
child.sayName() //'听风是风'


//ES6 class类
class Parent {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
};
const child = new Parent('echo', 26);
child.sayName() //echo

但new不该该像一个黑盒,咱们除了知道结果,更应该明白过程究竟如何。那么那么这篇文章主要围绕两点展开,第一,js中new一个对象时到底发生了什么第二,知道了原理后咱们经过js来实现一个简单的new方法前端

1、new操做中发生了什么?es6

比较直观的感受,当咱们new一个构造函数,获得的实例继承了构造器的构造属性(this.name这些)以及原型上的属性app

在《JavaScript模式》这本书中,new的过程说的比较直白,当咱们new一个构造器,主要有三步:函数

• 建立一个空对象,将它的引用赋给 this,继承函数的原型。
• 经过 this 将属性和方法添加至这个对象
• 最后返回 this 指向的新对象,也就是实例(若是没有手动返回其余的对象)this

咱们改写上面的例子,大概就是这样:spa

// ES5构造函数
let Parent = function (name, age) {
    //1.建立一个新对象,赋予this,这一步是隐性的,
    // let this = {};
    //2.给this指向的对象赋予构造属性
    this.name = name;
    this.age = age;
    //3.若是没有手动返回对象,则默认返回this指向的这个对象,也是隐性的
    // return this;
};
const child = new Parent();

这应该不难理解,你应该在工做中看过相似下述代码中的操做,将this赋予一个新的变量(例如that),最后返回这个变量:prototype

// ES5构造函数
let Parent = function (name, age) {
    let that = this;
    that.name = name;
    that.age = age;
    return that;
};
const child = new Parent('听风是风', '26');

为何要这么写呢?我在前面说this的建立与返回是隐性的,但在工做中为了让构造过程更易可见与更易维护,因此才有了上述使用that代替this,同时手动返回that的作法;这也验证了隐性的这两步确实是存在的。rest

但上述这个解释我以为不够完美,它只描述了构造器属性是如何塞给实例,没说原型上的属性是如何给实例继承的。code

我在winter大神的重学前端专栏中,看到了比较符合我心意的,同时也是符合原理的描述:

• 以构造器的prototype属性为原型,建立新对象;
• 将this(也就是上一句中的新对象)和调用参数传给构造器,执行;
• 若是构造器没有手动返回对象,则返回第一步建立的对象

到这里无论怎么说,你都应该大概知道了new过程当中会新建对象,此对象会继承构造器的原型与原型上的属性,最后它会被做为实例返回这样一个过程。知道了原理,咱们来手动实现一个简单的new方法。

2、实现一个简单的new方法

// 构造器函数
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
//本身定义的new方法
let newMethod = function (Parent, ...rest) {
    // 1.以构造器的prototype属性为原型,建立新对象;
    let child = Object.create(Parent.prototype);
    // 2.将this和调用参数传给构造器执行
    let result = Parent.apply(child, rest);
    // 3.若是构造器没有手动返回对象,则返回第一步的对象
    return typeof result  === 'object' ? result : child;
};
//建立实例,将构造函数Parent与形参做为参数传入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';

//最后检验,与使用new的效果相同
child instanceof Parent//true
child.hasOwnProperty('name')//true
child.hasOwnProperty('age')//true
child.hasOwnProperty('sayName')//false

那么到这里就介绍完毕了。

new一个构造函数默认返回什么?调用构造函数不使用new能获得实例吗?若是你对这些有兴趣,能够阅读博主这篇博客:

精读JavaScript模式(三),new一个构造函数究竟发生了什么?

实例为何能使用构造器prototype上的方法?继承之间的关系又是怎么样的?若是你对这些有兴趣,能够阅读博主这篇博客:

精读JavaScript模式(八),JS类式继承

ES6新增的class类怎么用?与传统构造函数写法有哪些区别?如何快速上手class类?那你能够阅读博主这篇博客:

es6入门5--class类的基本用法

最后模拟实现new方法中,...rest是个什么参数?若是你对这个存疑,那怕是得了解下ES6中的取代arguments的rest参数,欢迎阅读这篇:

es6入门3--箭头函数与形参等属性的拓展

原谅个人厚颜无耻,若是你以为本文对你有所帮助,欢迎评论,点赞与关注

相关文章
相关标签/搜索