定義一個對象的最簡單的方法
var car = {
color:"red",
drive:function() {
alert(this.color + " car moved");
}
}
這個方法不是在非常有用,因爲它創建了一個單獨的對象,而這個對象和任何常見的數據結構沒有任何聯繫,爲了創建第二個car實例,必須重新定義它的結構.
通過構造函數創建一個新對象
function Car() {
this.color = "red";
this.drive = function(){
alert(this.color + " car moved");
}
}
var car = new Car();
car.drive();
JavaScript中的每個函數都有一個稱爲prototype的屬性.如果某個函數被用作構造函數,則這個屬性會被自動通過new調用創建對象的原型
function Car() {
this.color = "red";
}
Car.prototype.drive = function(){
alert(this.color + " car moved");
}
var car = new Car();
car.drive();
對prototype屬性所做的任何更改能夠應用於通過new Car()構造的每一個對象,不管它是在更改之前還是更改後創建.爲Car.prototype 添加新函數.對於共享相同原型的每一個對象,該函數都可以立即使用,無論它是在更改之前或是之後構造,具體如下:
// 更新原型
function Car(color) {
this.color = color;
}
Car.prototype.drive = function(){
alert(this.color + " car is driving");
}
var car1 = new Car("red");
alert(car1.__proto__ === Car.prototype); // true
car1.drive();
// 爲原型添加新的函數
Car.prototype.stop = function() {
alert(this.color + " car has stopped");
}
var car2 = new Car("blue");
// 共享同一對象原型的對象
alert(Object.getPrototypeOf(car1) === Object.getPrototypeOf(car2)); // true
// 這兩個對象現在都能訪問這個新的方法
car2.stop();
car1.stop();
面向對象的很重要一個特性就是繼承了,這裏只要介紹通過原型鏈繼承
// 繼承的基本設置
function Car(color) {
this.color = color;
}
Car.prototype.drive = function(){
alert(this.color + " car is driving");
}
Car.prototype.turn = function(direction) {
alert(this.color + " car turns " + direction);
}
Car.prototype.stop = function() {
alert(this.color + " car has stopped");
}
// 消防車
function FirTruck() {}
FirTruck.prototype.turnCannon = function(direction) {
alert("Cannon moves to the " + direction);
}
var truck = new FirTruck();
// 因爲Car.prototype 並不在truck對象的原型鏈中
// 因此方法move()並不可用
truck.move();
truck.turnCannon("right");
JavaScript中有一個很特殊的Object.create(proto, properties)方法, 注:IE8及以下不支持
它可以用來創建一個新的空白對象並將其原型設置爲proto
function Car(color) {
this.color = color;
}
Car.prototype.move = function(){
alert(this.color + " car is driving");
}
Car.prototype.turn = function(direction) {
alert(this.color + " car turns " + direction);
}
Car.prototype.stop = function() {
alert(this.color + " car has stopped");
}
if(!Object.create){
// 兼容性處理
FireTruck.prototype = Car.prototype;
}else{
FireTruck.prototype = Object.create(Car.prototype);
}
function FireTruck() {}
// 檢查,以防萬一
//alert(Object.getPrototypeOf(FireTruck.prototype) === Car.prototype);
// 如果爲true
// 則Car.prototype被添加到鏈中
FireTruck.prototype.turnCannon = function(direction){
alert("Cannon moves to the " + direction);
}
var truck = new FireTruck();
// 現在可以工作了,因爲Car.prototype已經在truck對象的原型鏈中
truck.move();
truck.turnCannon("right");
代碼可以運行,但其輸出還是存在一些問題
true
undefined car is driving
Cannon moves to the right
小汽車的color現在可以通過Car的構造函數進行設置.構造函數本身沒有執行,所以其color顯示爲undefined.這個問題很好解決,修改FireTruck構造函數,在其中添加對Car構造函數的調用,這樣Car就可以初始化它自己的對象變量
function FireTruck() {
Car.call(this, "red");
}
再次運行這段代碼,欣賞一下正確的輸出
即使該代碼能夠成功運行,但仍有一個小問題需要解決.當這個新函數創建時,它的prototype屬性並不爲空.它有一個稱爲constructor的屬性將引用函數本身,當調用
FireTruck.prototype = Object.create(Car.prototype);
時,該屬性丟失,因爲這個新建的對象並不具有自己的屬性.可以將丟失的屬性作爲第二個參數傳遞給create
FireTruck.prototype = Object.create(Car.prototype, {
constructor: {
value: FireTruck, // 和FireTruck.prototype.constructor一樣
enumerable: false,
writable: true,
configurable: true
}
});
這裏的constructor並不是通常的屬性.當對象的鍵值進行循環時,它不會出現,但可以通過名稱直接訪問.通過給create()的第二個參數傳遞屬性"描述符"可以取得相同的效果描述符具有如下所示的幾個字段
value: 初始值
enumerable: 如果屬性顯示在對象屬性的列表中, 在像for...in 這樣的循環或Object.keys中
writable: 如果屬性可以被指派一個不同的值
configurable: 如果描述符定義的規則可以被修改或其屬性可以刪除,則爲true
這樣就可以模仿真實的 constructor 的行爲
最終版本的的繼承示例
function extend(subConstructor, superConstructor) {
if(!Object.create){
subConstructor.prototype = superConstructor.prototype;
subConstructor.constructor = {
value: FireTruck, // 和FireTruck.prototype.constructor一樣
enumerable: false,
writable: true,
configurable: true
}
}else{
subConstructor.prototype = Object.create(superConstructor.prototype, {
constructor: {
value: FireTruck, // 和FireTruck.prototype.constructor一樣
enumerable: false,
writable: true,
configurable: true
}
});
}
}
function Car(color) {
this.color = color;
}
Car.prototype.move = function(){
alert(this.color + " car is driving");
}
Car.prototype.turn = function(direction) {
alert(this.color + " car turns " + direction);
}
Car.prototype.stop = function() {
alert(this.color + " car has stopped");
}
function FireTruck() {
Car.call(this, "red");
}
extend(FireTruck, Car);
FireTruck.prototype.turnCannon = function(direction){
alert("Cannon moves to the " + direction);
}
var truck = new FireTruck();
truck.move();
truck.turnCannon("right");