可以描述 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'