物件的建立
一種是透過 new 關鍵字//這個牽涉到建構子,稍後會提到 var banana = new Fruit();另一種則是使用 {} 宣告一個物件
//隱含的建立一個 javascript 內建的 Object 物件 var banana = { //物件屬性 color: 'yellow', size: '15cm', //物件方法 destroy: function() { alert('Noooooooooo!'); } };
建構子(Constructor)、物件屬性和物件方法的宣告
使用 function 宣告不只是可以建立函式,也可以建立一個建構子。而屬性和方法可以在建構子內宣告,這種方式相當於在每個物件建立時才把屬性和方法附加在物件上;不過這樣做有個缺點,如果父類別採用這種方式宣告,當存取父類別的屬性或方法時,會變成 undefined,因為屬性和方法是附加在每個建立好的物件上,而不是類別本身。//建構子乍看之下就只是一個函式而已 function Fruit(name, color) { //私用屬性(private) //其實就是區域變數的概念而已 var secret = 'You cant see this property.'; //公用屬性(public) this.name = name; this.color = color; //私用方法(private) function doNothing() {}; //公用方法(public) this.changeColor = function(newColor) { this.color = newColor; } }之後便可以透過 new 來產生新的類別實體
//建立類別實體 var fruit1 = new Fruit('banana', 'yellow'); var fruit2 = new Fruit('apple', 'red'); alert(fruit1 instanceof Fruit); //true alert(fruit1 === fruit2); //false alert(fruit1.color); //yellow fruit1.changeColor('green'); alert(fruit1.color); //green alert(typeof fruit1.secret); //undefined alert(typeof fruit1.doNothing); //undefined alert(typeof fruit1.stillDoNothing); //undefined但是如果直接對變數宣告屬性或方法,只會附加在目標變數指向的物件上,而不是類別本身。
//直接對變數宣告屬性 fruit1.looks = 'Like a banana.'; var fruit3 = new Fruit('grape', 'purple'); alert(fruit1.looks); //Like a banana. alert(typeof fruit3.looks); //undefiend
javascript 的 prototype 與繼承(Inheritance)
在 javascript 中物件的繼承跟 prototype 這個屬性有很大的關係。在取出物件的屬性時,會先去檢查該物件是否有直接定義目標屬性;若是沒有,則檢查該物件的 prototype 物件有沒有定義,如果還是沒有,會往 prototype chain (透過繼承將 prototype 鏈結起來)的上一層找,直到根部的 prototype 為止。特別要注意的是所有的物件都會隱含的參照到一個 prototype,但是只有 Function 物件(建構子)可以直接存取 prototype 屬性。
而物件的屬性和方法比較正規的宣告方式也是使用 prototype 來宣告,這樣做有一個好處,就是可以設定屬性初始值。
//改用繼承的方式來寫 //水果建構子 function Fruit(name) { this.name = name ? name : this.name; } //使用 prototype 作宣告並初始化 Fruit.prototype.name = 'Fruit'; Fruit.prototype.inFruit = 'inFruit'; Fruit.prototype.show = function() { alert(this.name); }; //香蕉建構子,香蕉是一種水果我跟你說 function Banana() { //呼叫父類別的建構子 this.super.call(this, 'Banana'); } //繼承自 Fruit //也是把 Banana 接上 Fruit 的 prototype chain Banana.prototype = new Fruit(); //修正 Banana 的建構子指標,根據網路上的說法他會指向 Fruit 的建構子 //但測試後,有沒有這行其實沒差,因為上面已經宣告過 Banana 的建構子了 Banana.prototype.constructor = Banana; //使用 prototype 作宣告並初始化 Banana.prototype.super = Fruit; //父類別參照(super)得自己宣告, //因為 javascript 不提供直接參 //照到父類別的變數 Banana.prototype.color = 'yellow'; Banana.prototype.changeColor = function(newColor) { this.color = newColor; }; //覆寫父類別的function Banana.prototype.show = function() { alert(this.name + '\'s color is ' + this.color + '.'); }; var banana = new Banana(); alert(banana instanceof Banana); //true alert(banana instanceof Fruit); //true alert(banana.inFruit); //inFruit banana.show(); //Banana's color is yellow. banana.changeColor('green'); banana.show(); //Banana's color is green.若要存取父類別的屬性或方法,還是要透過 prototype 來取得。
alert('Parent\'s name is ' + banana.super.prototype.name + '.'); //Parent's name is Fruit. banana.super.prototype.show(); //Fruit
沒有留言:
張貼留言