如何快速入門VUE3.0:進入學習
什麼是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;}