对于大部分前端开发者而言,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上的方法?继承之间的关系又是怎么样的?若是你对这些有兴趣,能够阅读博主这篇博客:
ES6新增的class类怎么用?与传统构造函数写法有哪些区别?如何快速上手class类?那你能够阅读博主这篇博客:
最后模拟实现new方法中,...rest是个什么参数?若是你对这个存疑,那怕是得了解下ES6中的取代arguments的rest参数,欢迎阅读这篇:
原谅个人厚颜无耻,若是你以为本文对你有所帮助,欢迎评论,点赞与关注。