物件導向 Object Oriented Programming(中國:面向對象)
不直接呼叫一個 function,而是對某個物件做操作
- 變成一個模組的感覺(把原本分散的 function 集中起來)
- 比較有規範
- 資訊可以被藏起來(封裝,外面不會知道裡面發生甚麼)
(ex. XHR 發 request 也是使用封裝)
需要去思考別人該怎麼使用會比較方便add() // 直接呼叫一個 function add myWallet.add() // 對 myWallet 這個物件呼叫 function add
開始使用物件導向
用 class(類別,好比一個設計圖) 去寫一個物件,用 new (好比實體化的東西) 去呼叫 function
- 出現在 class 裡面的 function 叫做 method
- new 出來的東西叫做 instance
- private 的東西不能被外面存取,public 的東西則可以任意更動
- 使用 getter、setter 可以去決定一些事情(在 function 裡面寫點甚麼來限制甚麼)
ES6 寫法:
用 constructor 去設定初始值class Dog { // setter 去設定甚麼 constructor(name) { // 建構子 php 用 __construct this.name = name } // getter 去拿取甚麼 getName() { return this.name } sayHello() { console.log(this.name) } } var d = new Dog() d.setName('abc') d.sayHello() // abc
ES5 寫法:
function Dog(name) { // 相當於 ES6 的 constructor
this.name = name
}
Dog.prototype.getName = function() {
return this.name
}
Dog.prototype.sayHello = function() {
console.log(this.name)
}
var d = new Dog('abc')
var b = new Dog('qweqwe')
d.sayHello()
運作機制
d.sayHello()
運作流程:
- 看 d 身上有沒有 sayHello,如果沒找到就往上一層找
- 看
d.___proto___
有沒有 sayHello,如果沒找到就再往上一層找
(d.___proto___
===dog.prototype
) - 看
d.___proto___.___proto___
有沒有 sayHello,如果沒有就在往上一層找
(d.___proto___.___proto___
===object.prototype
)(object 不知道是哪來的) - 看
d.___proto___.___proto___.___proto___
有沒有 sayHello - 回傳 null,表示找到頂了
prototype chain 原型鏈
- 共同享有一個 function
繼承
當有共同屬性時,不需要重寫一個,可以用繼承的方式繼承原本寫好的
- 用 extends 去繼承
當在繼承裡建立一個 constructor 時,要呼叫 super(),用來呼叫上一層的 constructor,且把參數一起傳上去class Dog { constructor(name) { this.name = name } sayHello() { console.log(this.name) } } class BlackDog extends Dog { test() { console.log('test!', this.name) } } const d = new BlackDog('hello') d.sayHello() // hello
class BlackDog extends Dog {
constructor(name) {
super(name) // php 是用 parent
this.sayHello()
}
test() {
console.log('test!', this.name)
}
}
const d = new BlackDog('hello')
d.sayHello() // hello hello
static
static 的東西不屬於 instance,屬於 class 的
static function 靜態 function
static variable 靜態變數
this
- 在非物件導向的地方使用 this,this 代表的東西會依據環境而有所不同,瀏覽器的跟 node.js 的 this 不同(瀏覽器-window、node.js-global)
- this 的值跟他在甚麼時候被定義沒有關係,重點是怎麼去呼叫,判別值的方法可以用 .call() 的方式去看,看.call() 前面的前面接的東西
'use strict'; const obj = { a: 123, inner: { test: function() { console.log(this) } } } obj.inner.test() // 可以看成 obj.inner.test.call(obj.inner) const func = obj.inner.test func() // 可以看成 func.call(undefined)
嚴格模式 use strict
使用嚴格模式後,在非物件導向的地方使用 this,不管在哪個環境都會是 undefined
'use strict'
function test() {
console.log(this) // undefined
}
test()
.call()、.apply()
裡面傳的第一個參數可以改變 this 的值,function 的參數寫在第一個參數後面
- .call():function 的參數用逗號隔開
- .apply():function 的參數用 array 包起來
'use strict'
function test(a, b, c) {
console.log(this) // undefined
}
test.call(123, 1, 2, 3)
test.apply(123, [1, 2, 3])
.bind()
綁定 this 的值
'use strict'
const obj = {
a: 1,
test: function() {
console.log(this)
}
}
const bindTest = obj.test.bind('jkjk')
bindTest.call(123) // jkjk
箭頭函式的 this
跟怎麼去呼叫沒關係,重點是在那裡定義
class Test {
run() {
console.log('run this', this)
setTimeout(() => {
console.log(this)
}, 1000)
}
}
const t = new Test()
t.run() // run 跟 setTimeout 的 this 會一樣