<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在 6 月更文中零零散散講了 JS 的物件建立和物件繼承,有工友對此還是表示疑惑,要注意:這是兩個不同但又相關的東西,千萬別搞混了!
這些文章是:
本篇作為彙總篇,來一探究竟!!沖沖衝
不難發現,每一篇都離不開工廠、構造、原型這 3 種設計模式中的至少其一!
讓人不禁想問:JS 為什麼非要用到這種 3 種設計模式了呢??
正本溯源,先從物件建立講起:
我們本來習慣這樣宣告物件(不用任何設計模式)
let car= { price:100, color:"white", run:()=>{console.log("run fast")} }
當有兩個或多個這樣的物件需要宣告時,是不可能一直複製寫下去的:
let car1 = { price:100, color:"white", run:()=>{console.log("run fast")} } let car2 = { price:200, color:"balck", run:()=>{console.log("run slow")} } let car3 = { price:300, color:"red", run:()=>{console.log("broken")} }
這樣寫:
肯定是要封裝啦,第一個反應,可以 藉助函數 來幫助我們批次建立物件~
於是乎:
function makeCar(price,color,performance){ let obj = {} obj.price = price obj.color= color obj.run = ()=>{console.log(performance)} return obj } let car1= makeCar("100","white","run fast") let car2= makeCar("200","black","run slow") let car3= makeCar("300","red","broken")
這就是工廠設計模式在 JS 建立物件時應用的由來~
到這裡,對於【物件建立】來說,應該夠用了吧?是,在不考慮擴充套件的情況下,基本夠用了。
但這個時候來個新需求,需要建立 car4、car5、car6 物件,它們要在原有基礎上再新增一個 brand
屬性,會怎麼寫?
第一反應,直接修改 makeCar
function makeCar(price,color,performance,brand){ let obj = {} obj.price = price obj.color= color obj.run = ()=>{console.log(performance)} obj.brand = brand return obj } let car4= makeCar("400","white","run fast","benz") let car5= makeCar("500","black","run slow","audi") let car6= makeCar("600","red","broken","tsl")
這樣寫,不行,會影響原有的 car1、car2、car3 物件;
那再重新寫一個 makeCarChild
工廠函數行不行?
function makeCarChild (price,color,performance,brand){ let obj = {} obj.price = price obj.color= color obj.run = ()=>{console.log(performance)} obj.brand = brand return obj } let car4= makeCarChild("400","white","run fast","benz") let car5= makeCarChild("500","black","run slow","audi") let car6= makeCarChild("600","red","broken","tsl")
行是行,就是太麻煩,全量複製之前的屬性,建立 N 個相像的工廠,顯得太蠢了。。。
於是乎,在工廠設計模式上,發展出了:建構函式設計模式,來解決以上覆用(也就是繼承)的問題。
function MakeCar(price,color,performance){ this.price = price this.color= color this.run = ()=>{console.log(performance)} } function MakeCarChild(brand,...args){ MakeCar.call(this,...args) this.brand = brand } let car4= new MakeCarChild("benz","400","white","run fast") let car5= new MakeCarChild("audi","500","black","run slow") let car6= new MakeCarChild("tsl","600","red","broken")
建構函式區別於工廠函數:
到此為止,工廠函數的複用也解決了。
新的問題在於,我們不能通過查詢原型鏈從 MakeCarChild 找到 MakeCar
car4.__proto__===MakeCarChild.prototype // true MakeCarChild.prototype.__proto__ === MakeCar.prototype // false MakeCarChild.__proto__ === MakeCar.prototype // false
無論在原型鏈上怎麼找,都無法從 MakeCarChild
找到 MakeCar
這就意味著:子類不能繼承父類別原型上的屬性
這裡提個思考問題:為什麼“要從原型鏈查詢到”很重要?為什麼“子類要繼承父類別原型上的屬性”?就靠 this 繫結來找不行嗎?
於是乎,建構函式設計模式 + 原型設計模式 的 【組合繼承】應運而生
function MakeCar(price,color,performance){ this.price = price this.color= color this.run = ()=>{console.log(performance)} } function MakeCarChild(brand,...args){ MakeCar.call(this,...args) this.brand = brand } MakeCarChild.prototype = new MakeCar() // 原型繼承父類別的構造器 MakeCarChild.prototype.constructor = MakeCarChild // 重置 constructor let car4= new MakeCarChild("benz","400","white","run fast")
現在再找原型,就找的到啦:
car4.__proto__ === MakeCarChild.prototype // true MakeCarChild.prototype.__proto__ === MakeCar.prototype // true
其實,能到這裡,就已經很很優秀了,該有的都有了,寫法也不算是很複雜。
但,總有人在追求極致。
上述的組合繼承,父類別建構函式被呼叫了兩次,一次是 call 的過程,一次是原型繼承 new 的過程,如果每次範例化,都重複呼叫,肯定是不可取的,怎樣避免?
工廠 + 構造 + 原型 = 寄生組合繼承 應運而生
核心是,通過工廠函數新建一箇中間商 F( ),複製了一份父類別的原型物件,再賦給子類的原型;
function object(o) { // 工廠函數 function F() {} F.prototype = o; return new F(); // new 一個空的函數,所佔記憶體很小 } function inherit(child, parent) { // 原型繼承 var prototype = object(parent.prototype) prototype.constructor = child child.prototype = prototype } function MakeCar(price,color,performance){ this.price = price this.color= color this.run = ()=>{console.log(performance)} } function MakeCarChild(brand,...args){ // 建構函式 MakeCar.call(this,...args) this.brand = brand } inherit(MakeCarChild,MakeCar) let car4= new MakeCarChild("benz","400","white","run fast")
car4.__proto__ === MakeCarChild.prototype // true MakeCarChild.prototype.__proto__ === MakeCar.prototype // true
再到後來,ES6 的 class 作為寄生組合繼承的語法糖:
class MakeCar { constructor(price,color,performance){ this.price = price this.color= color this.performance=performance } run(){ console.log(console.log(this.performance)) } } class MakeCarChild extends MakeCar{ constructor(brand,...args){ super(brand,...args); this.brand= brand; } } let car4= new MakeCarChild("benz","400","white","run fast")
car4.__proto__ === MakeCarChild.prototype // true MakeCarChild.prototype.__proto__ === MakeCar.prototype // true
有興趣的工友,可以看下 ES6 解析成 ES5 的程式碼:原型與原型鏈 - ES6 Class的底層實現原理 #22
最後本瓜想再談談關於 JS 物件和函數的關係:
即使是這樣宣告一個物件,let obj = {}
,它一樣是由建構函式 Object
構造而來的:
let obj = {} obj.__proto__ === Object.prototype // true
在 JS 中,萬物皆物件,物件都是有函數構造而來,函數本身也是物件。
對應程式碼中的意思:
// 1. Object.__proto__ === Function.prototype // true // 2. Function.prototype.__proto__ === Object.prototype // true
這個設計真的就一個大無語,大糾結,大麻煩。。。
只能先按之前提過的歪理解記著先:Function 就是上帝,上帝創造了萬物;Object 就是萬物。萬物由上帝創造(物件由函數構造而來),上帝本身也屬於一種物質(函數本身卻也是物件);
對於本篇來說,繼承,其實都是父子建構函式在繼承,然後再由建構函式範例化物件,以此來實現物件的繼承。
到底是誰在繼承?函數?物件?都是吧~~
本篇由建立物件說起,講了工廠函數,它可以做一層最基本的封裝;
再到,對工廠的拓展,演進為建構函式;
再基於原型特點,構造+原型,得出組合繼承;
再追求極致,講到寄生組合;
再講到簡化書寫的 Es6 class ;
以及最後對物件與函數的思考。
更多關於JS物件建立繼承的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45