last updated:2013/05
參考文章:
談JavaScript使用prototype實作物件導向的探討
JavaScript使用物件導向技術來建立進階 Web 應用程式
Javascript繼承機制的設計思想
Javascript面向對象編程(二):構造函數的繼承
如同大多數語言一樣,Javascript的base class是Object
物件是一組 key / value 的dictionary
也因為如此,再加入新屬性、物件時也很寬鬆(抓錯當然也比較困難)
如下示範:
var newobj = {}; //等同 var newobj = new Object();
var obj = {"liar" : 4, "test" : new Date()};
obj.test2 = " new object!! "; //能隨時加入新屬性的特性
delete obj.test2; //簡單的刪除屬性方法
alert(obj.liar);
alert(obj["test"]);
delete運算符使用上還是有限制,可以參考這篇文章
JavaScript可輕易建立全域變數,但全域變數的使用會削弱程式的彈性
減少全域變數的使用的方法之一是建立唯一的全域變數,然後用它來保存應用程式
var MyApp = {};
MyApp.obj1 = {
"first": "test",
last: {
alfa: 1,
beta: 2
}
};
function在Javascript中也是物件,等同於class的使用
所以下列寫法均有相同效果
//1
function func(x){
alert(x);
}
func("show1");
//2
var func = function(x){
alert(x);
};
func("show2");
//3
var func = new Function("x", "alert(x);"); //Function類別也是確實可行
func("show3");
Javascript的this指標會指向呼叫的物件本身,如下範例:
function displayQuote() {
// this會依據呼叫的物件而改變
alert(this.memorableQuote);
}
var williamShakespeare = {
"memorableQuote": "It is a wise father that knows his own child.",
"sayIt" : displayQuote //引用 displayQuote
};
var markTwain = {
"memorableQuote": "Golf is a good walk spoiled.",
"sayIt" : displayQuote //引用 displayQuote
};
var oscarWilde = {
"memorableQuote": "True friends stab you in the front."
};
williamShakespeare.sayIt();
markTwain.sayIt();
/*
oscarWilde 則示範了另一種引用方式
每個function都有call()這個funciton, 會將傳入的物件作為其本身(this)來使用
*/
displayQuote.call(oscarWilde);
call()和另一個沒提到的apply()能將丟進去的物件指定為this
兩個函式的差別在於後續要傳入的參數形式,後續可看到示範
.call(oscarWilde, 參數1, 參數2, ...etc)
.apply(oscarWilde, 參數陣列)
使用this時要注意,如果沒指定物件作為this指向的對象時
則有可能覆寫全域函式,如下示範:
alert("NaN is NaN: " + isNaN(NaN)); //true
function x() {
this.isNaN = function() {
return "changed!";
};
}
x(); //指定物件的意思是例如宣告var test = new x(); ,test的isNaN()的this指向自己
alert("NaN is NaN: " + isNaN(NaN)); //changed!
this的使用上需注意內層函式的this不是連結到外層的this, 而是直接連結到全域變數
這違反直覺的設計算是JavaScript的程式設計錯誤之一
解決方式是建立一個變數儲存外層的this給內層函式使用:
obj.double = function () {
var t = this;
var helper = function () {
t.value = ...
};
helper();
};
回頭看Javascipt建立物件的過程
使用類別的過程如下:
function Animal(describe) {
this.describe = describe;
this.action = function () {
alert(describe);
};
}
var obj1 = new Animal("eat");
obj1.action();
/*
new Animal這行等同於
var obj1 = {};
Animal.call(obj1, "eat");
建立新物件後將它設為function的this值
*/
使用new關鍵字時,Javascript會先建立一個空物件
接著設定物件的prototype指向建構式的prototype
然後呼叫建構式並將所建立的空物件設為this
prototype是JavaScript獨特的機制,意義等同於類別的屬性
每次在Javascript建立一個物件,其實就是複製一次類別的內容(前面說過類別也是物件)
若上例建立100個animal物件,在過程中也一併建立了100個action
而同一個類別的物件不管複製多少個,都會共用相同的屬性(prototype 物件)
所以這個概念衍伸出,如果類別裡有共用的物件或方法,在設計的時候就應該把它想成屬性
每次建立物件時就不會重複建立內部物件,以減少資源的浪費
prototype示範如下:
function Animal(describe) {
this.describe = describe;
Animal.prototype.action = function () {
alert(describe);
};
}
var obj1 = new Animal("eat");
var obj2 = new Animal("sleep");
//注意!輸出皆是sleep,因為共用的關係,所以action會被後續的obj2覆蓋
obj1.action();
obj2.action();
prototype 本身是用object產生的物件,所以也都有著Object.prototype
函式的情況是綁在Function.prototype,Function.prototype再綁到 Object.prototype 上
Javascript使用函式的過程會是這樣,以toString()為例
先在物件本身尋找function > 接著往物件的prototype上找 > 再往prototype的prototype=Object.prototype上找
所以可以知道所有的物件都從Object繼承了toString()
這種鏈狀結構被稱為原型鏈
每個 prototype 都能取得constructor屬性指向其建構式
因為原型鏈的機制,物件可以取得 constructor 屬性
這個 constructor 的來源就是物件的 prototype 的 constructor
所以相同建構式 new 出來的物件會有相同的 constructor 屬性
在JavaScript製作物件靜態方法或變數的方式如下,注意必須在建構式後才能加入靜態方法或變數:
function ST() {}
ST.show = function () {
return "hey";
};
alert(ST.show());
接著是以Closure模擬 private 屬性,先看以下程式碼
function Person(name, age) {
this.getName = function () {
return name;
};
this.setName = function (newName) {
name = newName;
};
this.getAge = function () {
return age;
};
this.setAge = function (newAge) {
age = newAge;
};
}
關鍵點在於建構式中傳進去的name跟age會成為無法被外層直接存取的區域變數
只能透過 getName、getAge等方法對這兩個區域變數進行處理
上述的作法是以類別成員的方式建立對外開放的函式
實際上有做法能讓開放的介面意象更明確
var animal = function() {
var name = 'tom';
var API = {
"getName": function(){ return name;}
};
return API;
}();
alert(animal.getName());
從外部無法存取函式內的區域變數,所以封裝了 'name'
將存取的 function 集中在 'API' 物件中並回傳,表明只能透過 'API'介面裡的方法作處理
物件導向的另一重要特性是繼承機制
讓程式碼得以重複使用以提高開發效率
繼承的實現方式在繼承機制一文中解釋
參考文章:
談JavaScript使用prototype實作物件導向的探討
JavaScript使用物件導向技術來建立進階 Web 應用程式
Javascript繼承機制的設計思想
Javascript面向對象編程(二):構造函數的繼承
如同大多數語言一樣,Javascript的base class是Object
物件是一組 key / value 的dictionary
也因為如此,再加入新屬性、物件時也很寬鬆(抓錯當然也比較困難)
如下示範:
var newobj = {}; //等同 var newobj = new Object();
var obj = {"liar" : 4, "test" : new Date()};
obj.test2 = " new object!! "; //能隨時加入新屬性的特性
delete obj.test2; //簡單的刪除屬性方法
alert(obj.liar);
alert(obj["test"]);
delete運算符使用上還是有限制,可以參考這篇文章
JavaScript可輕易建立全域變數,但全域變數的使用會削弱程式的彈性
減少全域變數的使用的方法之一是建立唯一的全域變數,然後用它來保存應用程式
var MyApp = {};
MyApp.obj1 = {
"first": "test",
last: {
alfa: 1,
beta: 2
}
};
function在Javascript中也是物件,等同於class的使用
所以下列寫法均有相同效果
//1
function func(x){
alert(x);
}
func("show1");
//2
var func = function(x){
alert(x);
};
func("show2");
//3
var func = new Function("x", "alert(x);"); //Function類別也是確實可行
func("show3");
Javascript的this指標會指向呼叫的物件本身,如下範例:
function displayQuote() {
// this會依據呼叫的物件而改變
alert(this.memorableQuote);
}
var williamShakespeare = {
"memorableQuote": "It is a wise father that knows his own child.",
"sayIt" : displayQuote //引用 displayQuote
};
var markTwain = {
"memorableQuote": "Golf is a good walk spoiled.",
"sayIt" : displayQuote //引用 displayQuote
};
var oscarWilde = {
"memorableQuote": "True friends stab you in the front."
};
williamShakespeare.sayIt();
markTwain.sayIt();
/*
oscarWilde 則示範了另一種引用方式
每個function都有call()這個funciton, 會將傳入的物件作為其本身(this)來使用
*/
displayQuote.call(oscarWilde);
call()和另一個沒提到的apply()能將丟進去的物件指定為this
兩個函式的差別在於後續要傳入的參數形式,後續可看到示範
.call(oscarWilde, 參數1, 參數2, ...etc)
.apply(oscarWilde, 參數陣列)
使用this時要注意,如果沒指定物件作為this指向的對象時
則有可能覆寫全域函式,如下示範:
alert("NaN is NaN: " + isNaN(NaN)); //true
function x() {
this.isNaN = function() {
return "changed!";
};
}
x(); //指定物件的意思是例如宣告var test = new x(); ,test的isNaN()的this指向自己
alert("NaN is NaN: " + isNaN(NaN)); //changed!
this的使用上需注意內層函式的this不是連結到外層的this, 而是直接連結到全域變數
這違反直覺的設計算是JavaScript的程式設計錯誤之一
解決方式是建立一個變數儲存外層的this給內層函式使用:
obj.double = function () {
var t = this;
var helper = function () {
t.value = ...
};
helper();
};
回頭看Javascipt建立物件的過程
使用類別的過程如下:
function Animal(describe) {
this.describe = describe;
this.action = function () {
alert(describe);
};
}
var obj1 = new Animal("eat");
obj1.action();
/*
new Animal這行等同於
var obj1 = {};
Animal.call(obj1, "eat");
建立新物件後將它設為function的this值
*/
使用new關鍵字時,Javascript會先建立一個空物件
接著設定物件的prototype指向建構式的prototype
然後呼叫建構式並將所建立的空物件設為this
prototype是JavaScript獨特的機制,意義等同於類別的屬性
每次在Javascript建立一個物件,其實就是複製一次類別的內容(前面說過類別也是物件)
若上例建立100個animal物件,在過程中也一併建立了100個action
而同一個類別的物件不管複製多少個,都會共用相同的屬性(prototype 物件)
所以這個概念衍伸出,如果類別裡有共用的物件或方法,在設計的時候就應該把它想成屬性
每次建立物件時就不會重複建立內部物件,以減少資源的浪費
prototype示範如下:
function Animal(describe) {
this.describe = describe;
Animal.prototype.action = function () {
alert(describe);
};
}
var obj1 = new Animal("eat");
var obj2 = new Animal("sleep");
//注意!輸出皆是sleep,因為共用的關係,所以action會被後續的obj2覆蓋
obj1.action();
obj2.action();
prototype 本身是用object產生的物件,所以也都有著Object.prototype
函式的情況是綁在Function.prototype,Function.prototype再綁到 Object.prototype 上
Javascript使用函式的過程會是這樣,以toString()為例
先在物件本身尋找function > 接著往物件的prototype上找 > 再往prototype的prototype=Object.prototype上找
所以可以知道所有的物件都從Object繼承了toString()
這種鏈狀結構被稱為原型鏈
每個 prototype 都能取得constructor屬性指向其建構式
因為原型鏈的機制,物件可以取得 constructor 屬性
這個 constructor 的來源就是物件的 prototype 的 constructor
所以相同建構式 new 出來的物件會有相同的 constructor 屬性
在JavaScript製作物件靜態方法或變數的方式如下,注意必須在建構式後才能加入靜態方法或變數:
function ST() {}
ST.show = function () {
return "hey";
};
alert(ST.show());
接著是以Closure模擬 private 屬性,先看以下程式碼
function Person(name, age) {
this.getName = function () {
return name;
};
this.setName = function (newName) {
name = newName;
};
this.getAge = function () {
return age;
};
this.setAge = function (newAge) {
age = newAge;
};
}
關鍵點在於建構式中傳進去的name跟age會成為無法被外層直接存取的區域變數
只能透過 getName、getAge等方法對這兩個區域變數進行處理
上述的作法是以類別成員的方式建立對外開放的函式
實際上有做法能讓開放的介面意象更明確
var animal = function() {
var name = 'tom';
var API = {
"getName": function(){ return name;}
};
return API;
}();
alert(animal.getName());
從外部無法存取函式內的區域變數,所以封裝了 'name'
將存取的 function 集中在 'API' 物件中並回傳,表明只能透過 'API'介面裡的方法作處理
物件導向的另一重要特性是繼承機制
讓程式碼得以重複使用以提高開發效率
繼承的實現方式在繼承機制一文中解釋
留言
張貼留言