new一个对象的详细过程,手动实现一个 new操作符
可以描述 new一个对象的详细过程,手动实现一个 new操作符
1. new 一个对象的详细过程:(原文地址)
首先我们看下new Person输出什么?
var Person = function(name, age) { this.name = name; this.age = age; }; Person.prototype.show = function() { console.log(this.name, this.age); }; var p = new Person("bella", 10); console.log(p);
有属性name, age 和 __proto__
__proto__里面有原型方法show,constructor, __proto__
然后我们再输出构造器Person.prototype:
对比一下,发现p的__proto__的值就是构造函数Person的prototype的属性值。
因此new操作符创建对象可以分为以下四个步骤:
① 创建一个空对象;
② 链接到原型(将所创建对象的__proto__属性值设为构造函数的prototype属性值);
③ 绑定this(构造函数中的this指向新对象并且调用构造函数);
④ 返回新对象。
因此上面的过程就可以等同于下面的过程:
var Person = function(name, age) { this.name = name; this.age = age; }; Person.prototype.show = function() { console.log(this.name, this.age); }; // var p = new Person("bella", 10); var p = {}; p.__proto__ = Person.prototype; Person.call(p, "balle", 10); console.log(p);
2. 手动实现一个new操作符:(原文地址)
要手动实现 new 操作符,就要明白new操作符做了什么事,如 上面 总结的new操作符创建对象的四个步骤。
这样我们就可以实现一个new方法了:
function realizeNew () { //创建一个新对象 let obj = {}; //获得构造函数 let Con = [].shift.call(arguments); //链接到原型(给obj这个新生对象的原型指向它的构造函数的原型) obj.__proto__ = Con.prototype; //绑定this let result = Con.apply(obj,arguments); //确保new出来的是一个对象 return typeof result === "object" ? result : obj }
[].shift.call(arguments)的作用是将调用realizeNew方法的第一个值拿出来:
我们实现的realizeNew()需要传入的参数是:构造函数 + 属性
首先创建一个新对象,
然后通过 arguments 类数组我们可以知道参数中包含了构造函数以及我们调用create时传入的其他参数,接下来就是要想如何得到其中这个构造函数和其他参数,由于arguments是类数组,没有直接的方法可以供其使用,我们可以有以下两种方法:
1)Array.form(arguments).shift();转换成数组,使用数组方法shift将第一项弹出
2)[].shift().call(arguments);通过call()让arguments能够借用shift()方法
绑定this的时候需要注意:
1)给构造函数传入属性,注意构造函数的this属性;
2)参数传进Con对obj的属性复制,this要指向obj对象;
3)在Con内部手动指定函数执行时的this使用call、apply实现
最后需要返回一个对象
测试:
function Person (name,age){ this.name = name; this.age = age; this.say = function () { console.log("I am " + this.name) } } //通过new创建构造实例 let person1 = new Person("Curry",18); console.log(person1.name); //"Curry" console.log(person1.age); //18 person1.say(); //"I am Curry' //通过realize()方法创造实例 let person2 = realizeNew (Person,"Curry",18); console.log(person2.name); //"Curry" console.log(person2.age); //18 person2.say(); //"I am Curry'