JS Object Oriented === ###### tags: `JS物件導向` ## 目錄 [TOC] ## Syllabus - Creating our own objects using object literal notation - JS classes and constructors - Inheritance - Method Chaining - Prototype and Prototype inheritance ## Everything in JS, is an Object - Objects in JS are quite like objects in real life - They have properties & things they can do (methods) - 但部分JS的東西都是Object,但null並不是、primitive type也都不是 - 但就算不是object,JS也可以把他暫時包裝成Object來擁有部分的property。 ## Object setting ``` var userOne = { email: 'ryu@ninjas.com', name: 'Ryu', login(){ console.log(this.email, 'has logged in'); }, logout(){ console.log(this.email, 'has logged out'); } }; userOne.login(); userOne.logout(); ``` 若想輸出userOne裡面的property可以有幾種做法 - A.b ``` userOne.name //Ryu ``` - A['b'] ``` userOne.['name'] //Ryu ``` 這種好處是可以動態調整b的狀況下是以下這樣 ``` prop = name userOne.[prop] //Rye prop=email userOne.[prop] //ryu@ninjas.com ``` ## Class 基本上是ES6弄出來的一種模仿(emulate)類似class的語法糖(syntactic sugar),主要還是依照prototype的方式在進行著。 所以每當我們要讓一個class被使用的時候都會使用new 這個new可以帶來下面幾件事情 - 開啟一個新的空物件 - 把this的作用域設定在這個物件中 - 呼叫constructor method ```js Class User { constructor(email, name) { this.email = email // 這個裡面的email就寫成外面給進來的 this.name = name //裡面的name就寫成外面pass進來的 } } var userOne = new User('ryu@ninjas.com', 'Ryu') var userTwo = new Useer('yoshi@mariokorp.com', 'Yoshi') ``` ## class method 若你想把method一起放進去讓他可以被繼承,可以這樣寫 記得property寫完中間不用放逗號‘,‘,自然寫下去就可以了 ```js class User { constructor(email, name) { this.email = email this.name =name } login() { console.log(this.email, 'just logged in ') } logout() { console.log(this.email, 'just logged out') } } ``` ## method chaining 你一定想過要連續使用method,但一班function沒有辦法直接做,我們可以透過一些手段來做成a.b.b.b.b的連續鎖鏈 ```js class User { constructor(email, name) { this.email = email; this.name = name; this.score = 0; } login() { console.log(this.email, 'just logged in ') return this; } logout() { console.log(this.email, 'just logged out') return this; } updateScore() { console.log(this.email, 'score is now', this.score); return this; } } var userOne = new User('ryu@ninjas.com', 'Ryu') ``` 這樣就可以寫成下面這樣 ```js userOne.login().updateScore().updateScore().logout() ``` ## Class Inheritence 若要實作讓一個user有特別的function可以用下面這種寫法。 我想新建一個admin讓他可以有刪除的功能,但又不想讓一般的user有這個方式,就可以用extend讓他繼承本來的。 讓他有本來user功能然後可以自己新增一些功能。 ```js class User { constructor(email, name) { this.email = email; this.name = name; this.score = 0; } login() { console.log(this.email, 'just logged in ') return this; } logout() { console.log(this.email, 'just logged out') return this; } updateScore() { console.log(this.email, 'score is now', this.score); return this; } } class Admin extends User { deleteUser(user) { users =users.filter(u => { return u.email != user.email; }) } } var admin = new Admin('shaun@ninjas.com', 'shaun') var users = [userOne, userTwo] admin.deletterUser(userTwo) ``` ## Prototype 在es6使用class之前,基本上都是使用prototype來做物件的規劃,js基本上沒有class的狀況,都還是利用prototype建立,class只是表層 但下面這種寫法,function並沒有進prototype裡面,instance的proto並不可能有效的調用 ```js function User(email, name) { this.email = email; this.name = name; this.online = false; this.login = function() { console.log(this.email, 'has logged in '); } } ``` 若想有效調用proto相關的寫法會是如下,以下userOne的proto裡面就會有相關的function可以調用了 ```js function User(email, name) { this.email = email; this.name = name; this.online = false; } User.prototype.login = function() { this.online = true; console.log(this.email, 'has logged in'); } User.prototype.logout = function() { this.online = false; console.log(this.email, 'hos logged out'); } var userOne = new User('ryu@ninjas.com', 'Ryu') console.log(userOne) ``` ## Prototype Inheritance 若要繼承prototype然後再自定義其他的fucntion可以用下面的方式,這樣也可以產生一個prototype chain讓同一個object同時有不同的proto。 若要新增function也可以用Admin.prototype來新增,但這只會落在Admin這個proto裡面,不會落在User的Proto中。 一整個chain proto就會變成Admin->user->object。在瀏覽器展開後會看到。 ```js function User(email, name) { this.email = email; this.name = name; this.online = false; } User.prototype.login = function() { this.online = true; console.log(this.email, 'has logged in'); } User.prototype.logout = function() { this.online = false; console.log(this.email, 'hos logged out'); } //繼承user function Admin(...args) { User.aply(this,args); this.role= 'super admin' //只有在admin裡面才有的role } Admin.prototype = Object.create(User.prototype) //新增function Admin.prototype.deleteUser = function(u) { users = users.filter(user => { return user.email != u.email )} } var userOne = new User('ryu@ninjas.com', 'Ryu') //建立admin var admin = new Admin('shaun@ninjas.com', 'Shaun') console.log(userOne) var users = [userOne, userTwo, admin]; ```