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];
```