前言
什么是new呢?
new運算子創建一個用戶定義的物件型別的實體或具有建構式的內置物件型別之一,
光看定義還是有幾分晦澀,直接看一個具體的例子,來了解一下JavaScript中的new實作的功能,
舉個例子
// 現實中瘦不了,但網路中一定要保持苗條
function Thin_User(name, age) {
this.name = name;
this.age = age;
}
Thin_User.prototype.eatToMuch = function () {
// 白日做夢吧,留下肥胖的淚水
console.log('i eat so much, but i\'m very thin!!!');
}
Thin_User.prototype.isThin = true;
const xiaobao = new Thin_User('zcxiaobao', 18);
console.log(xiaobao.name); // zcxiaobao
console.log(xiaobao.age); // 18
console.log(xiaobao.isThin); // true
// i eat so much, but i'm very thin!!!
xiaobao.eatToMuch();
通過上面這個例子,我們可以發現xiaobao可以:
- 訪問到建構式
Thin_User中屬性 - 訪問到
Thin_User.prototype中屬性
描述得更直白一點,new做了這些事:
- 創建了一個空物件,物件的
__proto__->Thin_User.prototype - 執行建構式,并將
this指向新物件 - 回傳新物件
補充說明
由于new是關鍵字,我們無法像模擬陣列高階方法一樣覆寫,因此我們寫一個函式createObject,來模擬new的效果,使用具體如下:
function Thin_User(name, age) {}
const u1 = new Thin_user(...)
const u2 = createObject(Thin_User, ...a\)
初步模擬
根據上面分析,createObject撰寫的大致步驟為:
- 創建一個新物件
obj - 設定
obj.__proto__->constructor.prototype(但JavaScript不推薦直接修改__proto__屬性,提供了setPrototypeOf方法來專門修改原型) - 使用
constructor.call/apply(obj, ...),將屬性添加到obj上 - 回傳
obj
__proto__和prototype,可以看JavaScript之徹底理解原型與原型鏈
call/apply,可以看JavaScript之手撕call、apply
學習完這些,我們就可以撰寫第一版代碼:
function createObject(Con) {
// 創建新物件obj
// var obj = {};也可以
var obj = Object.create(null);
// 將obj.__proto__ -> 建構式原型
// (不推薦)obj.__proto__ = Con.prototype
Object.setPrototypeOf(obj, Con.prototype);
// 執行建構式
Con.apply(obj, [].slice.call(arguments, 1));
// 回傳新物件
return obj;
}
回傳值效果
眾所周知,函式是有回傳值的,那建構式如果有回傳值,最終執行new后回傳的結果是怎樣的那?
回傳值為基本型別
假設建構式回傳值為一個基本型別,我們來看一下最后的回傳結果:
function Thin_User(name, age) {
this.name = name;
this.age = age;
return 'i will keep thin forever';
}
Thin_User.prototype.eatToMuch = function () {
console.log('i eat so much, but i\'m very thin!!!');
}
Thin_User.prototype.isThin = true;
const xiaobao = new Thin_User('zcxiaobao', 18);
console.log(xiaobao.name); // zcxiaobao
console.log(xiaobao.age); // 18
console.log(xiaobao.isThin); // true
// i eat so much, but i'm very thin!!!
xiaobao.eatToMuch();
最后的回傳結果好像受到任何干擾,難道建構式不會對回傳值進行處理嗎?
不急,我們來接著測驗一下回傳值為物件的情況,
回傳值為物件
function Thin_User(name, age) {
this.name = name;
this.age = age;
return {
name: name,
age: age * 10,
fat: true
}
}
Thin_User.prototype.eatToMuch = function () {
// 白日做夢吧,留下肥胖的淚水
console.log('i eat so much, but i\'m very thin!!!');
}
Thin_User.prototype.isThin = true;
const xiaobao = new Thin_User('zcxiaobao', 18);
// Error: xiaobao.eatToMuch is not a function
xiaobao.eatToMuch();
當我執行eatToMuch時,控制臺直接報錯,沒有當前函式,于是我列印了xiaobao物件:

發現xiaobao物件的age發生了改變,而且增加了fat屬性,正好與建構式的回傳值一樣,
看完這兩個例子,基本可以理清建構式有回傳值的情況:當建構式回傳值為物件時,直接回傳這個物件,
終版模擬
function createObject(Con) {
// 創建新物件obj
// var obj = {};也可以
var obj = Object.create(null);
// 將obj.__proto__ -> 建構式原型
// (不推薦)obj.__proto__ = Con.prototype
Object.setPrototypeOf(obj, Con.prototype);
// 執行建構式,并接受建構式回傳值
const ret = Con.apply(obj, [].slice.call(arguments, 1));
// 若建構式回傳值為物件,直接回傳該物件
// 否則回傳obj
return typeof(ret) === 'object' ? ret: obj;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/305480.html
標籤:其他
