Date: 2019/10/20
Lecturer: 土豆
OOP = Object Oriented Programming
物件導向
Class
Object
設計圖
實際的東西
實例化
Attributes
Methods
Class的組成
Class
學生
舉個例子
Object
小明
Attributes
Name
Age
Weight
Height
Methods
Walk
Eat
Sleep
Attributes
Name: 小明
Age: 20
Weight: 77
Height: 188
Methods
Walk
Eat
Sleep
分工合作,各司其職
Object A
Object B
Public
Attritube 1
Attritube 2
Method 1
Method 2
Private
Attritube 1
Method 1
Public
Attritube 1
Attritube 2
Method 1
Method 2
Private
Attritube 1
Method 1
Interface
Getter
讓別的Object取得自己的Property的Interface
Setter
讓別的Object可以設定自己的Property的Interface
Static
不需要實例化Class即可直接使用
站在巨人的肩膀上
Class
學生
Attributes
Name
Age
Weight
Height
Methods
Walk
Eat
Sleep
Class
好學生
Class
壞學生
Methods
Study
Methods
Fight
騎在你爸爸頭上
Class
學生
Methods
Walk (正常走)
Eat (一般吃法)
Sleep (一般睡法)
Class
懶學生
Methods
Walk (一搖一擺)
Eat (狼吞虎嚥)
Sleep (呼呼大睡)
一樣名稱
不同動作
class Rabbit {
constructor(type) {
this.type = type;
}
speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
}
let killerRabbit = new Rabbit("killer");
let blackRabbit = new Rabbit("black");
拆成兩部分來看
constructor()
methods
this.type指的是"實例出"的object裡面叫做type的property
//let type = "what??";
class Rabbit {
constructor(type) {
this.type = type;
}
speak(line) {
console.log(`The ${type} rabbit says '${line}'`);
}
}
let killerRabbit = new Rabbit("killer");
console.log(killerRabbit.type)
killerRabbit.speak();
刪掉this看看,並試著在class外定義一個type
constructor裡面的東西會在新建object時跑一次
class Apple {
constructor() {
console.log("An apple a day keeps doctor away.");
}
}
let a = new Apple();
你可以這樣在class中定義method
class Apple {
constructor() {
console.log("An apple a day keeps doctor away.");
}
run() {
console.log("Your apple keeps you away.");
}
}
let a = new Apple();
a.run();
現在辦不到,以後可能辦的到
你現在只能在constructor或是methods裡面定義
class Apple {
constructor() {
console.log("You create an apple!");
}
run() {
console.log("Your apple run away.");
}
}
class PoisionApple extends Apple {
constructor() {
super();
this.type = "Poision";
console.log("This is a poision apple!");
}
}
let a = new PoisionApple();
透過extends來繼承
super()代表呼叫父類別的constructor
// class Apple ...
class PoisionApple extends Apple {
constructor() {
super();
this.type = "Poision";
console.log("This is a poision apple!");
}
run() {
console.log("Your apple runs away, and kill a potato with poision.");
}
}
let a = new PoisionApple();
a.run();
在子類別中定義一樣名稱的method來覆蓋父類別的method
class Apple {
constructor() {
this.first_name = "";
this.last_name = "";
console.log("You create an apple!");
}
run() {
console.log("Your apple run away.");
}
get name() {
return this.first_name + " " + this.last_name;
}
set name(str) {
let temp = str.split(" ");
this.first_name = temp[0];
this.last_name = temp[1];
}
}
let a = new Apple();
a.name = "John Doe";
console.log(a.first_name);
console.log(a.last_name);
console.log(a.name);
在method前面加上set, get
class Apple {
// ...
static listAllSize() {
return ["small", "medium", "big"];
}
}
console.log(Apple.listAllSize());
在method前面加上static
注意這邊沒有任何實例化,但是卻可以呼叫class裡面的method
相對於dynamic被實例化時才放到記憶體中
static代表一開始就在記憶體中
class Apple {
// ...
}
class PoisionApple extends Apple {
// ...
}
let a = new PoisionApple();
console.log(a instanceof PoisionApple);
console.log(a instanceof Apple);
let b = new Apple();
console.log(b instanceof PoisionApple);
console.log(b instanceof Apple);
instanceof是一個operator
可以查看object是否是某一個class的實例,包含父類別
害我要解釋老半天...
因為一開始的應用單純
但是這老兄,不想設計Class卻設計了繼承......
所以才有了Prototype這東西
Brendan Eich
let empty = {};
console.log(empty.toString);
console.log(empty.toString());
先來跑跑看這段code
不覺得哪裡怪怪的嗎?
明明就沒有定義過toString這個Property阿
Object.prototype
Your Object
let empty = {};
console.log(Object.getPrototypeOf(empty) == Object.prototype);
為了證明我沒有唬爛你,94如此神奇
Your Another Object
console.log(Object.getOwnPropertyNames(Object.prototype));
來看看Object.prototype提供了什麼
Object.prototype
Your Object
Your Another Object
Calling toString()
Not Found
Not Found
Found!!
Call it
Object.prototype
Function.prototype
Your Function
來看看更多的chain
console.log(Object.getOwnPropertyNames(Function.prototype));
看看Function.protype提供了啥
Object.prototype
Array.prototype
Your Array
來看看更多的chain
console.log(Object.getOwnPropertyNames(Array.prototype));
看看Array.protype提供了啥
let protoRabbit = {
type: "none",
speak: function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
};
let killerRabbit = Object.create(protoRabbit);
killerRabbit.type = "killer";
killerRabbit.speak("SKREEEE!");
let sleepyRabbit = Object.create(protoRabbit);
sleepyRabbit.type = "sleepy";
sleepyRabbit.speak("zzzzzzz");
Object.create()
JavaScript class = constructor function + prototype property
// constructor function
function Rabbit(type) {
console.log("You create a new Rabbit!");
this.type = type;
}
// prototype property
Rabbit.prototype.speak = function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
};
// create a new Rabbit object
let weirdRabbit = new Rabbit("weird");
然後使用new去創建新的object
他老兄看到Java有new,所以他也想要
阿就沒有設計Class是要new什麼?
那就只好把function拿來new了
然後我:
來看看怎麼用function創建出object
function Dog(name) {
this.name = name;
this.type = "哈士奇";
this.speak = function() {
console.log(`我是${this.name},我要吃罐頭`);
}
}
let dogA = new Dog("Jack");
let dogB = new Dog("Dogy");
dogA.speak();
dogB.speak();
object的property不共用
function Dog(name) {
this.name = name;
this.type = "哈士奇";
this.speak = function() {
console.log(`我是${this.name},我要吃罐頭`);
}
}
let dogA = new Dog("Jack");
let dogB = new Dog("Dogy");
dogB.type = "柴犬";
console.log(dogA.type);
console.log(dogB.type);
每個object都有這個,功能一模一樣
this.speak = function() {
console.log(`我是${this.name},我要吃罐頭`);
}
// ...
console.log(dogA.speak === dogB.speak);
但是卻要各自佔掉一個記憶體空間
一個優秀的工程師不能忽略這件事情!!
function被建立時,會自動建立一個叫prototype的property
let foo = function() {
return "nothing";
}
console.log(Object.getOwnPropertyNames(foo));
這個prototype就是一個空的object
console.log(typeof(foo.prototype));
console.log(foo.prototype);
需要共用的東西就全部丟到這個prototype裡面
使用new創建新的object時,會自動繼承這個prototype
function Dog(name) {
this.name = name;
this.type = "哈士奇";
}
Dog.prototype.speak = function() {
console.log(`我是${this.name},我要吃罐頭`);
}
let dogA = new Dog("Jack");
let dogB = new Dog("Dogy");
console.log(Object.getPrototypeOf(dogA) === Dog.prototype);
console.log(Object.getPrototypeOf(dogB) === Dog.prototype);
console.log(dogA.speak === dogB.speak);
// constructor function
function Rabbit(type) {
console.log("You create a new Rabbit!");
this.type = type;
}
// prototype property
Rabbit.prototype.speak = function(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
};
// create a new Rabbit object
let weirdRabbit = new Rabbit("weird");
跟我念一遍~
真正的實現方式是 constructor function + prototype property
JavaScript的class是語法糖
利用class實作一個二維向量的type,要求如下
Properties
Methods
// Your code here.
console.log(new Vec(1, 2).plus(new Vec(2, 3)));
// → Vec{x: 3, y: 5}
console.log(new Vec(1, 2).minus(new Vec(2, 3)));
// → Vec{x: -1, y: -1}
console.log(new Vec(3, 4).length);
// → 5
使用範例
class Vec {
constructor(x, y) {
this.x = x;
this.y = y;
}
plus(vec) {
return new Vec(this.x + vec.x, this.y + vec.y);
}
minus(vec) {
return new Vec(this.x - vec.x, this.y - vec.y);
}
get length() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
}
// Your code here.
console.log(new Vec(1, 2).plus(new Vec(2, 3)));
// → Vec{x: 3, y: 5}
console.log(new Vec(1, 2).minus(new Vec(2, 3)));
// → Vec{x: -1, y: -1}
console.log(new Vec(3, 4).length);
// → 5
ANS
let data = {one: true, two: true, hasOwnProperty: true};
// Fix this call
console.log(data.hasOwnProperty("one"));
console.log(data.hasOwnProperty("three"));
之前我們使用過hasOwnProperty來檢查一個object當中有無某個property
現在我們把hasOwnProperty override掉了,請把它修好
let data = {
one: true,
two: true,
hasOwnProperty: function(str) {
return Object.prototype.hasOwnProperty.call(this, str);
}
}
console.log(data.hasOwnProperty("one"));
console.log(data.hasOwnProperty("three"));
ANS
請利用class實作一個stack的class,要求如下
Properties
Methods
// Your code...
let s = new Stack();
console.log(s.items);
// []
s.push(1);
s.push(2);
console.log(s.pop());
// 2
console.log(s.isEmpty());
// false
s.push("a");
s.push(true);
console.log(s.items);
// [1, 'a', true]
console.log(s.size);
// 3
使用範例
class Stack {
constructor() {
this.items = [];
}
push(item) {
this.items.push(item);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
get isEmpty() {
if(this.items.length == 0) {
return true;
} else {
return false;
}
}
get size() {
return this.items.length;
}
}
let s = new Stack();
console.log(s.items);
// []
s.push(1);
s.push(2);
console.log(s.pop());
// 2
console.log(s.isEmpty);
// false
s.push("a");
s.push(true);
console.log(s.items);
// [1, 'a', true]
console.log(s.size);
// 3
ANS