在 JavaScript 中,new 運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例。創建一個對象很簡單,為什麼我們還要多此一舉使用 new 運算符呢?它到底有什麼樣的魔力? ...
在 JavaScript 中,new 運算符創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例。創建一個對象很簡單,為什麼我們還要多此一舉使用 new 運算符呢?它到底有什麼樣的魔力?
認識 new 運算符
通過下麵的例子理解 new 運算符:
function Person (name) {
this.name = name
}
Person.prototype.getName = function () {
console.log(this.name)
}
var joe = new Person('joe')
joe.sayHello = function () {
console.log('Hello!')
}
joe.getName() // joe
joe.sayHello() // Hello!
Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function
Person 是一個普通的函數,當它與 new 運算符一起使用時,Person 就是一個構造函數。通過 new Person('joe') 得到的新對象 joe 繼承了 Person 的屬性,同時,this 也指向 joe 實例。為 joe 添加的屬性 sayHello 不會影響 Person,即 joe 是區別與 Person 的一個新對象。
因此,通過 new 創建的實例對象和構造函數之間建立了一條原型鏈,並通過原型鏈賦予實例對象繼承屬性的能力。
new 的原理和實現
通過上面的分析,new 運算符內部做瞭如下四個操作:
- 創建一個空的簡單 JavaScript 對象(即{});
- 鏈接新對象(即設置該新對象的構造函數)到函數對象;
- 將新創建的對象作為 this 的上下文;
- 如果該函數沒有返回對象,返回新創建的對象。
new 的實現如下:
function newOperator (ctor, ...args) {
var obj = {};
obj.__proto__ = ctor.prototype
var res = ctor.apply(obj, args)
return res || obj;
}
優化一下代碼:
function newOperator (ctor, ...args) {
var o = Object.create(ctor.prototype) // 合併第一和第二步:創建一個空的簡單 JavaScript 對象(即{}),鏈接新對象(即設置該新對象的構造函數)到函數對象
return fn.apply(o, args) || o
}
使用 newOperator 函數測試上面 Person 的例子:
function Person(name) {
this.name = name
}
Person.prototype.getName = function () {
console.log(this.name)
}
var joe = newOperator(Person, 'joe')
joe.sayHello = function () {
console.log('Hello!')
}
joe.getName() // joe
joe.sayHello() // Hello!
Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function
結果是一致的。
更好的檢查方式是:
function Person(name) {
this.name = name
}
console.log(new Person('joe')) // @1
console.log(newOperator(Person, 'joe')) // @2
@1 和 @2 在控制台的顯示信息是一模一樣的。