1. 程式人生 > 程式設計 >詳解JavaScript中new操作符的解析和實現

詳解JavaScript中new操作符的解析和實現

前言

new 運算子是我們在用建構函式建立例項的時候使用的,本文來說一下 new 運算子的執行過程和如何自己實現一個類似 new 運算子的函式。

new 運算子的執行過程

new 運算子的主要目的就是為我們建立一個使用者定義的物件型別的例項或具有建構函式的內建物件的例項(比如箭頭函式就沒有建構函式,所以是不能 new 的)。new 操作符的執行大概有以下幾個步驟:

  1. 建立一個新的空物件
  2. 把新物件的 __proto__ 連結到建構函式的 prototype 物件(每一個使用者定義函式都有一個 prototype 屬性指向一個物件,該物件有一個 constructor 屬性指向該函式),讓我們的公共屬性和方法可以從原型上繼承,不用每個例項都建立一次。
  3. 將第一步建立的新的物件作為建構函式的 this 的上下文,執行建構函式,建構函式的執行讓我們配置物件的私有屬性和方法。
  4. 執行建構函式,如果建構函式沒有返回值或者返回值不是一個物件,則返回 this

我麼可以用程式碼簡單表示上面的邏輯:

function new_ (constr,...rests) {
 var obj = {};
 obj.__proto__ = constr.prototype;
 var ret = constr.apply(obj,rests);
 return isPrimitive(ret) ? obj : ret; //判斷建構函式的返回值是否為物件,不是則直接返回建立的obj物件
}

new 的實現

上面講了 new 運算子的執行過程,下面我們來自己動手實現一個 new 運算子。

function new_(constr,...rests) {
 if (typeof constr !== "function") {
 throw "the first param must be a function";
 }
 new_.target = constr;
 var obj = Object.create(constr.prototype);
 var ret = constr.apply(obj,rests);
 var isObj = typeof ret !== null && typeof ret === "object";
 var isFun = typeof ret === "function";
 //var isObj = typeof ret === "function" || typeof ret === "object" && !!ret;
 if (isObj || isFun) {
 return ret;
 }
 return obj;
}

function Person(name,age) {
 this.name = name;
 this.age = age;
}
Person.prototype.say = function () {
 console.log(this.name);
};
var p1 = new_(Person,'clloz','28')
var p2 = new_(Person,'csx','31')
console.log(p1); //Person{name: "clloz",age: "28"}
p1.say(); //clloz
console.log(p2); //Person{name: "csx",age: "31"}
p2.say(); //csx

console.log(p1.__proto__ === Person.prototype); //true
console.log(p2.__proto__ === Person.prototype); //true

以上就是一個簡單的 new 實現,判斷是否為物件那裡可能不是很嚴謹,不過沒有想到更好的方法。

一個小補充,在 mdnFunction.prototype.apply() 詞條中看到的直接把方法寫到 Function.prototype 上,也是個不錯的思路,Function.prototype 在所以函式的原型鏈上,所以這個方法可以在每個函式上呼叫,方法內部的 this 也是指向呼叫方法的函式的。

Function.prototype.construct = function (aArgs) {
 var oNew = Object.create(this.prototype);
 this.apply(oNew,aArgs);
 return oNew;
};

強制用 new 呼叫建構函式

function Clloz(...arguments) {
 if (!(this instanceof Clloz)) {
 return new Clloz(...arguments)
 }
}

Tips

補充兩個關於 new 運算子的知識點。

  1. 上面提到 new 的執行過程的最後一步,如果建構函式沒有返回值或者返回值不是一個物件,則返回 this。但是如果返回的是一個 null 的話,依然返回 this,雖然 null 也算是 object
  2. new 操作符後面的建構函式可以帶括號也可以不帶括號,除了帶括號可以傳遞引數以外,還有一個重要的點是兩種用法的運算子優先順序不一樣,在JS運算子優先順序這篇文章中有提到,帶引數的 new 操作符的優先順序是比不帶引數的要高的,new Foo() > Foo() > new Foo

一般不太會遇到,可能有些題目會問這些問題。

以上就是詳解JavaScript中new操作符的解析和實現的詳細內容,更多關於JavaScript new解析和實現的資料請關注我們其它相關文章!