JavaScript中的new操作符的原理解析

JavaScript中new操作符用於創建一個給定構造函數的對象實例。如下例子:

function Person(name, age){
	this.name = name;
	this.age = age;
}
const person1 = new Person('Tom', 20)
console.log(person1)  // Person {name: "Tom", age: 20}

我們定義了一個構造函數Person,然後通過new操作符生成Person構造函數的一個實例並將其引用賦值給變量person1。然後控制檯打印出person1的內容,可以看到該實例對象具有nameage屬性,它們的值就是我們在調用構造函數時傳入的值。

那麼,我們使用new操作符的時候都發生了哪些事呢?

備註:如果對JS中的prototype__proto__constructor屬性不大熟悉的話,強烈建議先看一下這篇文章再來看一下內容:幫你徹底搞懂JS中的prototype、__proto__與constructor(圖解)

new關鍵字進行的操作

new關鍵字進行了如下的操作(爲了便於描述,obj用來表示創建的空對象、用constrc來表示構造函數):

  1. 創建一個空對象obj{});
  2. obj[[prototype]]屬性指向構造函數constrc的原型(即obj.[[prototype]] = constrc.prototype)。
  3. 將構造函數constrc內部的this綁定到新建的對象obj,執行constrc(也就是跟調用普通函數一樣,只是此時函數的this爲新創建的對象obj而已,就好像執行obj.constrc()一樣);
  4. 若構造函數沒有返回非原始值(即不是引用類型的值),則返回該新建的對象obj(默認會添加return this)。否則,返回引用類型的值。

這裏補充說明一下:[[prototype]]屬性是隱藏的,不過目前大部分新瀏覽器實現方式是使用__proto__來表示。構造函數的prototype屬性我們是可以顯式訪問的。

讓我們用圖來展示文章開頭的那個例子的過程:
new操作符的執行過程
怎麼樣,是不是對new操作符的執行過程有了一個清晰的瞭解了?

自己實現new操作符

從上面我們已經清楚地掌握了new的執行過程,那麼我們就動手來自己實現一下new操作吧!

function myNew(constrc, ...args) {
	const obj = {}; // 1. 創建一個空對象
	obj.__proto__ = constrc.prototype; // 2. 將obj的[[prototype]]屬性指向構造函數的原型對象
	// 或者使用自帶方法:Object.setPrototypeOf(obj, constrc.prototype)
	const result = constrc.apply(obj, args); // 3.將constrc執行的上下文this綁定到obj上,並執行
	return result instanceof Object ? result : obj;  //4. 如果構造函數返回的是對象,則使用構造函數執行的結果。否則,返回新創建的對象
}

// 使用的例子:
function Person(name, age){
	this.name = name;
	this.age = age;
}
const person1 = myNew(Person, 'Tom', 20)
console.log(person1)  // Person {name: "Tom", age: 20}

這裏的關鍵兩步就是:

  1. 將新創建對象的原型鏈設置正確,這樣我們才能使用原型鏈上的方法。
  2. 將新創建的對象作爲構造函數執行的上下文,這樣我們才能正確地進行一些初始化操作。

本文結束!

參考文獻:

  1. https://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript
  2. JavaScript new Keyword
  3. new operator
  4. JavaScript For Beginners: the ‘new’ operator
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章