摘要:深入系列第十二篇,通過的模擬實現(xiàn),帶大家揭開使用獲得構(gòu)造函數(shù)實例的真相一句話介紹運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構(gòu)造函數(shù)的內(nèi)置對象類型之一也許有點難懂,我們在模擬之前,先看看實現(xiàn)了哪些功能。
newJavaScript深入系列第十二篇,通過new的模擬實現(xiàn),帶大家揭開使用new獲得構(gòu)造函數(shù)實例的真相
一句話介紹 new:
new 運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構(gòu)造函數(shù)的內(nèi)置對象類型之一
也許有點難懂,我們在模擬 new 之前,先看看 new 實現(xiàn)了哪些功能。
舉個例子:
// Otaku 御宅族,簡稱宅 function Otaku (name, age) { this.name = name; this.age = age; this.habit = "Games"; } // 因為缺乏鍛煉的緣故,身體強度讓人擔憂 Otaku.prototype.strength = 60; Otaku.prototype.sayYourName = function () { console.log("I am " + this.name); } var person = new Otaku("Kevin", "18"); console.log(person.name) // Kevin console.log(person.habit) // Games console.log(person.strength) // 60 person.sayYourName(); // I am Kevin
從這個例子中,我們可以看到,實例 person 可以:
訪問到 Otaku 構(gòu)造函數(shù)里的屬性
訪問到 Otaku.prototype 中的屬性
接下來,我們可以嘗試著模擬一下了。
因為 new 是關(guān)鍵字,所以無法像 bind 函數(shù)一樣直接覆蓋,所以我們寫一個函數(shù),命名為 objectFactory,來模擬 new 的效果。用的時候是這樣的:
function Otaku () { …… } // 使用 new var person = new Otaku(……); // 使用 objectFactory var person = objectFactory(Otaku, ……)初步實現(xiàn)
分析:
因為 new 的結(jié)果是一個新對象,所以在模擬實現(xiàn)的時候,我們也要建立一個新對象,假設(shè)這個對象叫 obj,因為 obj 會具有 Otaku 構(gòu)造函數(shù)里的屬性,想想經(jīng)典繼承的例子,我們可以使用 Otaku.apply(obj, arguments)來給 obj 添加新的屬性。
在 JavaScript 深入系列第一篇中,我們便講了原型與原型鏈,我們知道實例的 __proto__ 屬性會指向構(gòu)造函數(shù)的 prototype,也正是因為建立起這樣的關(guān)系,實例可以訪問原型上的屬性。
現(xiàn)在,我們可以嘗試著寫第一版了:
// 第一版代碼 function objectFactory() { var obj = new Object(), Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; };
在這一版中,我們:
用new Object() 的方式新建了一個對象 obj
取出第一個參數(shù),就是我們要傳入的構(gòu)造函數(shù)。此外因為 shift 會修改原數(shù)組,所以 arguments 會被去除第一個參數(shù)
將 obj 的原型指向構(gòu)造函數(shù),這樣 obj 就可以訪問到構(gòu)造函數(shù)原型中的屬性
使用 apply,改變構(gòu)造函數(shù) this 的指向到新建的對象,這樣 obj 就可以訪問到構(gòu)造函數(shù)中的屬性
返回 obj
更多關(guān)于:
原型與原型鏈,可以看《JavaScript深入之從原型到原型鏈》
apply,可以看《JavaScript深入之call和apply的模擬實現(xiàn)》
經(jīng)典繼承,可以看《JavaScript深入之繼承》
復制以下的代碼,到瀏覽器中,我們可以做一下測試:
function Otaku (name, age) { this.name = name; this.age = age; this.habit = "Games"; } Otaku.prototype.strength = 60; Otaku.prototype.sayYourName = function () { console.log("I am " + this.name); } function objectFactory() { var obj = new Object(), Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; Constructor.apply(obj, arguments); return obj; }; var person = objectFactory(Otaku, "Kevin", "18") console.log(person.name) // Kevin console.log(person.habit) // Games console.log(person.strength) // 60 person.sayYourName(); // I am Kevin
[]~( ̄▽ ̄)~**
返回值效果實現(xiàn)接下來我們再來看一種情況,假如構(gòu)造函數(shù)有返回值,舉個例子:
function Otaku (name, age) { this.strength = 60; this.age = age; return { name: name, habit: "Games" } } var person = new Otaku("Kevin", "18"); console.log(person.name) // Kevin console.log(person.habit) // Games console.log(person.strength) // undefined console.log(person.age) // undefined
在這個例子中,構(gòu)造函數(shù)返回了一個對象,在實例 person 中只能訪問返回的對象中的屬性。
而且還要注意一點,在這里我們是返回了一個對象,假如我們只是返回一個基本類型的值呢?
再舉個例子:
function Otaku (name, age) { this.strength = 60; this.age = age; return "handsome boy"; } var person = new Otaku("Kevin", "18"); console.log(person.name) // undefined console.log(person.habit) // undefined console.log(person.strength) // 60 console.log(person.age) // 18
結(jié)果完全顛倒過來,這次盡管有返回值,但是相當于沒有返回值進行處理。
所以我們還需要判斷返回的值是不是一個對象,如果是一個對象,我們就返回這個對象,如果沒有,我們該返回什么就返回什么。
再來看第二版的代碼,也是最后一版的代碼:
// 第二版的代碼 function objectFactory() { var obj = new Object(), Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; var ret = Constructor.apply(obj, arguments); return typeof ret === "object" ? ret : obj; };下一篇文章
JavaScript深入之類數(shù)組對象與arguments
相關(guān)鏈接《JavaScript深入之從原型到原型鏈》
《JavaScript深入之call和apply的模擬實現(xiàn)》
《JavaScript深入之繼承》
深入系列JavaScript深入系列目錄地址:https://github.com/mqyqingfeng/Blog。
JavaScript深入系列預計寫十五篇左右,旨在幫大家捋順JavaScript底層知識,重點講解如原型、作用域、執(zhí)行上下文、變量對象、this、閉包、按值傳遞、call、apply、bind、new、繼承等難點概念。
如果有錯誤或者不嚴謹?shù)牡胤剑垊毡亟o予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎star,對作者也是一種鼓勵。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/82847.html
摘要:也就是說當返回的函數(shù)作為構(gòu)造函數(shù)的時候,時指定的值會失效,但傳入的參數(shù)依然生效。構(gòu)造函數(shù)效果的優(yōu)化實現(xiàn)但是在這個寫法中,我們直接將,我們直接修改的時候,也會直接修改函數(shù)的。 JavaScript深入系列第十一篇,通過bind函數(shù)的模擬實現(xiàn),帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會創(chuàng)建一個新函數(shù)。當這個新函數(shù)被調(diào)用時,bind() 的第一個參數(shù)...
摘要:寫在前面深入系列共計篇已經(jīng)正式完結(jié),這是一個旨在幫助大家,其實也是幫助自己捋順底層知識的系列。深入系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 深入系列共計 15 篇已經(jīng)正式完結(jié),這是一個旨在幫助大家,其實也是幫助自己捋順 JavaScript 底層知識的系列。重點講解了如原型、作用域、執(zhí)行上下文、變量對象、this、...
摘要:深入系列第十五篇,講解各種繼承方式和優(yōu)缺點。優(yōu)點融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點,是中最常用的繼承模式。寄生組合式繼承為了方便大家閱讀,在這里重復一下組合繼承的代碼組合繼承最大的缺點是會調(diào)用兩次父構(gòu)造函數(shù)。 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點。 但是注意: 這篇文章更像是筆記,哎...
摘要:深入系列第十篇,通過和的模擬實現(xiàn),帶你揭開和改變的真相一句話介紹方法在使用一個指定的值和若干個指定的參數(shù)值的前提下調(diào)用某個函數(shù)或方法。如果有錯誤或者不嚴謹?shù)牡胤?,請務必給予指正,十分感謝。 JavaScript深入系列第十篇,通過call和apply的模擬實現(xiàn),帶你揭開call和apply改變this的真相 call 一句話介紹 call: call() 方法在使用一個指定的 this...
摘要:深入系列第十四篇,講解創(chuàng)建對象的各種方式,以及優(yōu)缺點。也就是說打著構(gòu)造函數(shù)的幌子掛羊頭賣狗肉,你看創(chuàng)建的實例使用都無法指向構(gòu)造函數(shù)這樣方法可以在特殊情況下使用。 JavaScript深入系列第十四篇,講解創(chuàng)建對象的各種方式,以及優(yōu)缺點。 寫在前面 這篇文章講解創(chuàng)建對象的各種方式,以及優(yōu)缺點。 但是注意: 這篇文章更像是筆記,因為《JavaScript高級程序設(shè)計》寫得真是太好了! 1....
閱讀 992·2023-04-25 19:40
閱讀 3625·2023-04-25 17:41
閱讀 3086·2021-11-11 11:01
閱讀 2787·2019-08-30 15:55
閱讀 3313·2019-08-30 15:44
閱讀 1489·2019-08-29 14:07
閱讀 572·2019-08-29 11:23
閱讀 1406·2019-08-27 10:54