[第十七週] JavaScript 進階:物件導向(new、super、封裝)

文章推薦指數: 80 %
投票人數:10人

物件導向的寫法: ES5 VS ES6. 在ES6 之後,開始有了Class 這個語法糖可以使用,可以比較看看兩種不同版本的物件導向寫法: ... [第十七週]JavaScript進階:物件導向(new、super、封裝) 物件導向的寫法:ES5VSES6 在ES6之後,開始有了Class這個語法糖可以使用,可以比較看看兩種不同版本的物件導向寫法: ES6:Class classDog{ constructor(name){ this.name=name; } sayHello(){ console.log(this.name,'Hello'); } } consthappy=newDog('happy'); happy.sayHello(); constwhite=newDog('white'); white.sayHello(); ES5:建構函式+prototype functionDog(name){ this.name=name; } Dog.prototype.sayHello=function(){ console.log(this.name,'Hello'); } consthappy=newDog('happy'); happy.sayHello(); constwhite=newDog('white'); white.sayHello(); new關鍵字:模擬new在背後幫你做的事 在ES5時,通常是把function當成constructor來用,稱為「建構函式」,而共用的method則會放在prototype新增,可以避免在每個instance重複新增內容一樣的method。

而關鍵在於new關鍵字,用new出來的function,JS會在背後幫你做好一連串的機制。

下例是ES5的OOP寫法: functionDog(name){ this.name=name; } Dog.prototype.sayHi=function(){ console.log(this.name,'Hi'); } constwhite=newDog('white'); 用上面這個例子,來描述關鍵字new在背後到底做了什麼? 接下來以一個自己寫的functionnewDog('yello'),來模擬newDog('yello')在做的事: constyello=newDog('yello'); white.sayHi(); yello.sayHi(); 首先目的是通過自己寫的newDog產生一個instanceyello,希望這個instance會有跟用new出來的instancewhite有一樣的屬性跟方法。

所以目標放在如何寫出newDog()來模擬new這個關鍵字背後做的事情。

functionnewDog(name){ constobj={};//1. Dog.call(obj,name);//2. obj.__proto__=Dog.prototype;//3. returnobj;//4. } /* new背後做的事: 1.產生一個新object=>obj 2.把Dog當作constructor,將this指向obj,同時把參數name丟進去 =>因為Dog只有一個參數所以用call,如果是兩個以上的參數就可以用apply放陣列 3.將obj.__proto__指向Dog.prototype 4.回傳obj */ 繼承:super 在ES6使用繼承時,當要改寫子類別的constructor時,記得要先用super()父類的constructor,不然會跳出錯誤:Mustcallsuperconstructorinderivedclassbeforeaccessing'this'orreturningfromderivedconstructor。

classDog{ constructor(name){ this.name=name; } sayHi(){ console.log(this.name,'Hi'); } } classTaiwansDogextendsDog{ constructor(name){ super(name);//=>記得要先super() this.sayHi(); } } constwhite=newDog('white'); constblack=newTaiwansDog('black'); 練習封裝:實現privateproperty的幾種嘗試 之前這篇筆記:什麼是閉包Closure與實際應用裡,Closure最後一個wallet範例是說明Closure可以達到封裝的目的,讓我想到之前看YT上的JavaScriptOOP教學。

varmoney=100; functionadd(num){ money+=1; } functiondeduct(num){ if(num>10){ num-=10; } else{ money-=num; } } add(1); deduct(30); console.log(money);//91 在ES5要實現Class中的私有屬性,也是在function(建構函式)內部宣告一個變數,之後再利用用getter&setter去存取privateproperty。

那後來又想著,那到底要如何在ES6中的Class實現private屬性呢? 查了一下PrivatepropertiesinJavaScriptES6classes,第2,3個回答得到不少啟發,尤其是第3個列舉了不同方法跟說明,認識到Symbols類型,雖然不是真正意義上的private,但還是滿酷的! 想說練習一下,直接把wallet範例把多餘的method刪掉,改成以下三種: ES5-function模擬Class版(realprivate) ES6-constructor版(realprivate) ES6-Symbols版(halfprivate) 1.ES5-function模擬Class版(realprivate) 很標準的ES5封裝方法。

functionWallet(init){ letmoney=init; this.getMoney=function(){ returnmoney; } }; constwallet=newWallet(100); console.log(wallet.getMoney()); console.log(wallet.money);//=>存取不到,真正的private 2.ES6-constructor版(realprivate) 需要存取privateproperty的method都只能放在constructor裡面,是可以正常運作,但感覺不太對勁 classWallet{ constructor(num){ var_money=num; this.getMoney=()=>_money; this.setMoney=(newNum)=>_money=newNum; } }; constwallet=newWallet(100); console.log(wallet.getMoney()); console.log(wallet._money);//=>存取不到,真正的private 3.ES6-Symbols版(halfprivate) 就是看著範例用,沒有深究,只覺得新語法很酷 varmoney=Symbol(); classWallet{ constructor(num){ this[money]=num; } getMoney(){ returnthis[money]; } }; constwallet=newWallet(100); console.log(wallet.getMoney()); console.log(wallet[money]);//=>還是存取得到,不是真正的private 結論 所以在ES6實現privateproperty最方便的寫法是什麼? 沒有。

對,真的就是沒有。

而如果ES7的支援性越來越高,要實現privateproperty就有更方便的#關鍵字可以用,但現在ES6還沒有看到通用的方法,最簡單的方法其實可以再privatepropertyormethod的名稱加上_前綴,同事們可以很簡單看出這是個私有屬性,沒事不要去動它。

(以上內容大部分是程式導師實驗計畫第三期的學習筆記,如有錯誤歡迎糾正,非常感謝🤓) Writtenon August 11th, 2019 byYakimshu Feelfreetoshare! Youmayalsoenjoy: [第十七週]JavaScript進階:為什麼要有原形鍊PrototypeChain? [第十七週]JavaScript進階:出乎意料的this [第十七週]JavaScript進階:從作用域鍊ScopeChain來理解Closure原理 [第十七週]JavaScript進階:什麼是閉包Closure與實際應用 [第十七週]JavaScript進階:從EC來理解Hoisting [第十七週]JavaScript進階:打好基礎的第一步,從了解什麼是EC開始 [第十七週]JavaScript進階:Primitive&Object原始類型與物件的差異



請為這篇文章評分?