在 Javascript 中, 除了 Primitive value (number, string, boolean, null, undefined) 以外, 從字串 (String) 與陣列 (Array) 等核心功能, 到以 Javascript 建置的瀏覽器 API, 都可以算是物件 (Object).
物件 (Object) 是一批 "數據" 及 "功能" 的集合, 一般我們稱做 "屬性" (properties) 和方法 (methods).
物件可以裝載相關資料與程式碼, 當你要用物件塑造某個 thing, 我們會在這個物件設置屬性來定義這個 thing 的資訊, 設置方法實現這個 thing 的行為.
var person = {
name: 'William',
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
},
};
// constructor function
function Person(name) {
this.name = name;
}
var person = new Person('William');
常有人說 Javascript 是原型架構的程式語言, 一個物件都具備一組原型物件作為範本物件, 用來繼承其屬性與方法. 物件的原型物件也可能包含原型物件, 這就是我們所謂的原型鍊 (Prototype chain)
講到繼承,JavaScript 就只有一個建構子:物件。每個物件都有一個連著其他原型(prototype)的私有屬性(private property)物件。原型物件也有著自己的原型,於是原型物件就這樣鏈結,直到撞見 null 為止:null 在定義裡沒有原型、也是原型鏈(prototype chain)的最後一個鏈結。
簡而言之,就是一個物件可以提取並取用另一個物件的 Property 跟 Method.
一個物件除了我們給予的屬性值以外還包含原型 Prototype。當 > Object 查找不到 Property 或 Method,它會沿著 Prototype chain 去查找 Property 或 Method。
原型鏈上的屬性的查詢時間,可能會對效能有負面影響,對程式碼也因而產生明顯問題。另外,試圖尋找不存在的屬性,就一定會遍歷整個原型鏈。 接著,在迭代物件屬性時,每個原型鏈的枚舉屬性都會抓出來。
要檢查物件本身有沒有指定的屬性、也不需要查找整個原型鏈時,你必須使用由 Object.prototype 繼承的 hasOwnProperty 方法。
原型 (Prototype) 是 Javascript 物件用以互相繼承功能的機制, 與典型的 OO 程式語言中的繼承方式有所不同.
function Person(name) {
this.name = name;
}
Person.prototype = {
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
},
}
function Engineer(name) {
Person.call(this, name);
}
Engineer.prototype = Object.create(Person.prototype);
Engineer.prototype.coding = function() {
alert('I am typing the keyboard.');
}
Engineer.prototype.constructor = Engineer;
const engineer = new Engineer('William');
語法
Object.create(proto[, propertiesObject])
範例
var Person = {
name: 'Default',
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
},
};
var person = Object.create(Person);
person.name = 'Arron';
傳統的 OOP 都是先定義類別, 當使用類別建立物件實例後, 根據類別上所定義的所有屬性與函式複製到此實例. 但 Javascript 不會複製這些屬性與函式, 使用原型鍊去連接這些屬性與函式.
ES6 推出了 Classes 讓我們在建立物件實例及繼承時, 用法上與傳統 OOP 語言類似.
class Person {
constructor(name) {
this.name = name;
}
greeting() {
alert('Hi! I\'m ' + this.name + '.');
}
}
class Engineer extends Person {
constructor(name) {
super(name);
}
coding() {
alert('I am typing the keyboard.');
}
}
在自己的程式碼裡,特別是剛接觸或小型專案時,你用繼承的頻率可能沒那麼高。若沒真正需要,只是「為使用而使用」繼承,老實說只是浪費時間。但隨著程式碼規模越來越大,你就會找到使用的時間。如果你發現自己開始建立類似功能的多個物件時,就可先建立通用的物件類型,來概括所有共用的功能,並在特定物件類型中繼承這些功能,既方便又有效率。