Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2019-10-12] 進階 JavaScript - 物件導向基礎與 prototype #9

Open
gracekrcx opened this issue Oct 13, 2019 · 2 comments
Open
Labels
JS201 JS201

Comments

@gracekrcx
Copy link
Owner

gracekrcx commented Oct 13, 2019

物件導向的基礎

(這是一個箱子裡,有多個你已定義好的功能(你想要的功能),有需要你可以一直複製相同箱子的故事)
(在物件導向的世界裡,不太會有直接去 call 一個 function 的情形,例如 add(),通常會是對一個物件做操作,例如:obj.add())

ECMAScript 6 中引入了類別 (class) 作為 JavaScript 現有原型程式(prototype-based)繼承的語法糖。

類別語法並不是要引入新的物件導向繼承模型到 JavaScript 中,而是提供一個更簡潔的語法來建立物件和處理繼承。
(JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.)

ES6 class

// class 像是一個設計圖
class Dog {
 setName(name){
  this.name = name // 這裡的 this 就是呼叫他的人,操控這個 instance 的人,在這裡就是 d
  console.log('this-->',this) // Dog {name: "PooBoo"}
 }
 sayHello(){
  console.log(this.name)
 }
}

var d = new Dog() // instance : 用 new 這個關鍵字去實體化
d.setName('PooBoo')
d.sayHello()
var d2 = new Dog()
console.log(d.sayHello() === d2.sayHello()) // true

ES6 class - Constructor

class Dog {
 // 在 new 的時候,其實就是在 call 這個 constructor 
 // 在被 new 時就會 call 這個 function 所以很適合做一些初始化的事情
 constructor(name) {
  this.name = name
 }
}

var d = new Dog('aaa') // new 時帶入參數

ES5 的 class 做了什麼

  1. 用一個 function 去實作 constructor
  2. 用 prototype 去實作 method

♥♥♥
ES5 裡可以把一個 function 當作一個 constructor 用,new 一個 function 產生一個 instance,背後的機制 javascript 會做好

---> 屬性,method 都放在 constructor

// 這個 function 就是 constructor
function Dog(name) {
 this.name = name
 this.getName = function() {
  return this.name
 }
}
var b = new Dog('FooPan')
var d = new Dog('BooPoo')
console.log( b.getName == d.getName)
// false,如果這樣寫 new 幾個 Dog 就會有幾個 getName function
// 因為 function 記憶體位置是不一樣的
// 比較好的寫法是 Dog.prototype.getName 
// 使用 prototype 寫法
function Dog(name) {
 this.name = name
 }
}
// 在 Dog 的 prototype 上加一個 function
Dog.prototype.getName = function(){
 return this.name
}
Dog.prototype.sayHello = function(){
 console.log(this.name)
}

var b = new Dog('FooPan')
var d = new Dog('BooPoo')
console.log(d) // d 就是 Dog 的 instance

console.log(b.getName === d.getName) // true

// d.__proto__ 是什麼
{getName: ƒ, sayHello: ƒ, constructor: ƒ}

// Dog.prototype(d.__proto__) 有 method and constructor
console.log(d.__proto__ === Dog.prototype) // true
console.log(Dog.__proto__ === Function.prototype) // true

instance 和 prototype 之間是如何串連的

  1. 透過屬性 __proto__
  2. 在 new 一個 instance 時,javascript 就幫你加了一個屬性 __proto__
soo.__proto__ === Dog.prototype  // true

從 prototype 來看「原型鍊」__proto__

instance 身上有 getName (但這樣就會有一直重複複製相同的 function 的問題)

結論:

  1. 會先找 instance 裡有沒有 getName()
  2. 如果沒有才會去 proto
function Dog(name) {
 this.name = name
 this.getName = function() {
  return 'MyName'
 }
}

Dog.prototype.getName = function(){
 return this.name
}

var soo = new Dog('Soo')
console.log(soo.getName())
// 'MyName'

d 的 instance 身上沒有 sayHello,所以往上找 proto

prototype chain 原型練

d.sayHello()
查找順序

  1. d
    身上有沒有 sayHello
  2. d.__proto__
    有沒有 sayHello
  3. d.__proto__.__proto__
    有沒有 sayHello
  4. d.__proto__.__proto__.__proto__
    有沒有 sayHello // null
  5. null 出現代表已經是最上層了
d.sayHello()

d.__proto__ === Dog.prototype
d.__proto__.__proto__ === Object.prototype  // 更上層
Dog.prototype.__proto__ === Object.prototype  // true

// 所以也可以在 Object 上設定 sayHello

Object.prototype.sayHello = function(){
 console.log('Object', this.name)
}

prototype
prototype

string.toUpperCase

透過 __proto__這個屬性,可以知道 s.toUpperCase 就是 String.prototype.toUpperCase() 這個 function

var s = 'abcd'
var newS = s.toUpperCase() 

s.toUpperCase === String.prototype.toUpperCase //true
s.__proto__ === String.prototype // true
s.__proto__.toUpperCase() === String.prototype.toUpperCase() // true

new 做了什麼事?

  1. 產生一個新的 object
  2. 執行 constructor,完成物件初始化,有了物件
  3. __proto__ 產生關聯
// 產生一個新的 Object

function Dog(name) {
 this.name = name
 this.getName = function() {
  return name
 }
}

var soo = new Dog('Soo')
{
 name : 'Soo'
 getName : function(){ return name }
}
function test() {
 console.log(this)
}
test.call(true)  // 第一個參數就會是 this
function Dog(name){
 this.myName = name
}

Dog.prototype.sayHello = function(){
 console.log(this.myName)
}

var booPoo = newDog('booPoo') // newDog 要做 new 做的事情
booPoo.sayHello() // booPoo

// new 在做什麼
function newDog(name){
 var obj = {} // 產生一個新的 object

 Dog.call(obj, name) // 執行 constructor
 console.log(obj) // {myName: "booPoo"}

 obj.__proto__ = Dog.prototype // 用 __proto__ 產生關聯
 return obj
}

物件導向的繼承:Inheritance

繼承就像人會遺傳父母的DNA

  1. 有共同的屬性時,就不用重複做一樣的東西
  2. 父母有的東西,你都可以用
  3. javascript 裡強制在用 this 前要先 call super()
class Dog {
 constructor(obj){
  console.log('1-->')
  this.name = obj.name
  this.age = obj.age
 }

 sayHello(){
  console.log(this.name)
 }
}
// BlackDog 繼承 Dog,Dog有的屬性 BlackDog 都可以用
class BlackDog extends Dog {
 // 沒有 constructor 所以他會去找他父層的 constructor 
 test(){
  console.log('test!', this) // BlackDog {name: "Black", age: undefined}
 }
}

const pooBoo = new BlackDog({name : 'Black'})
pooBoo.test()

BlackDog 自己加上 constructor

class Dog {
 constructor(obj){
  this.name = obj.name
  this.age = obj.age
 }

 sayHello(){
  console.log(this.name)
 }
}

class BlackDog extends Dog {
 constructor(obj){
  super(obj) 
  // 這裏 call super() 就是在 call 父層的 constructor
  // call Dog.constructor,強制這裡一定要 call super() 
  // 去避免沒有初始化就直接用 this call function
  this.sayHello()
 }
 test(){
  console.log('test!', this) // BlackDog {name: "Black", age: undefined}
 }
}

const pooBoo = new BlackDog({name : 'Black'})
pooBoo.test()

參考文章

Classes

@gracekrcx gracekrcx reopened this Dec 29, 2019
@gracekrcx
Copy link
Owner Author

gracekrcx commented Jun 15, 2020

我覺得的物件導向開發

是一些功能的模組,變得比較有規範

例如:一個錢包

需要的功能有

  1. 存錢
  2. 領錢
  3. 查詢戶頭裡的餘額

例如:會員個人資料模組

需要的功能有

  1. 上傳照片
  2. 新增個人資料
  3. 修改個人資料
  4. 查詢會員點數

例如:一隻狗

狗應該會有的行為,應該每隻狗都會有

  1. 會跑
  2. 會叫
  3. 會翻滾

@gracekrcx
Copy link
Owner Author

在 ES6

可以使用 class 語法去寫物件導向

在 ES5

使用 function 當作 constructor 搭配 prototype 語法去寫物件導向

@gracekrcx gracekrcx added the JS201 JS201 label Jun 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JS201 JS201
Projects
None yet
Development

No branches or pull requests

1 participant