面向對象的JavaScript 三 ----- prototype
本文主要介紹javascript中另文容易產生誤解和誤用的prototype屬性。
prototype是functions對象的屬性,也是在javascript中實現繼承的面向對象機制的關鍵,所以有必要弄懂prototype屬性。
首先看看一個普通對象的prototype屬性是什麼:
>>> typeof foo.prototype
"object"
看來所有對象最終都是繼承object的,這和java等語言一樣。
通過prototype可以給function加上函數和屬性。
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
};
或者,用下面這種寫法:
Gadget.prototype = {
price: 100,
rating: 3,
getInfo: function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
}
};
使用prototype增加屬性,該屬性是不會拷貝到每個function實例的.這個表示,你可以修改一個function實例的prototype屬性,這個修改會作用到所有實例上.這有點類似java中的類的static成員變量。
接下來看一個實例,讓你理解js engine在查找prototype屬性的方法:
function Gadget(name) {
this.name = name;
}
Gadget.prototype.name = 'foo';
>>> var toy = new Gadget('camera');
>>> toy.name;
"camera"
>>> delete toy.name;
true
>>> toy.name;
"foo"
如果訪問的是prototype 屬性,js 回找不到,然後會找到constructor的prototype。所以在delete後,第二次調用name返回的是“foo”
那麼如何遍歷得到一個對象的prototype屬性呢?可以這樣:
for (var prop in newtoy) {
console.log(prop + ' = ' + newtoy[prop]);
}
如果你想區分prototype屬性,可以這樣寫:
如果你想區分,可以使用:
>>> newtoy.hasOwnProperty('name')
true
>>> newtoy.hasOwnProperty('price')
false
或者合在一起:
for (var prop in newtoy) {
if (newtoy.hasOwnProperty(prop)) {
console.log(prop + '=' + newtoy[prop]);
}
}
每個對象還有isPrototypeOf方法,作用如下:
var monkey = {
hair: true,
feeds: 'bananas',
breathes: 'air'
};
function Human(name) {
this.name = name;
}
Human.prototype = monkey;
>>> var george = new Human('George');
>>> monkey.isPrototypeOf(george)
true
這個是不是讓你想到繼承。在之後的文章裏我會詳細講解繼承部分。
最後介紹一個很有趣的東西,看看下面的代碼:
>>> function Dog(){this.tail = true;}
>>> var benji = new Dog();
>>> var rusty = new Dog();
>>> Dog.prototype.say = function(){return 'Woof!';}
>>> benji.say();
"Woof!"
>>> benji.constructor;
Dog()
現在一切都很正常。
但是我們在做一點試驗
>>> benji.constructor.prototype.constructor
Dog()
現在讓我們覆蓋prototype
>>> Dog.prototype = {paws: 4, hair: true};
然後調用試試
>>> typeof benji.paws
"undefned"
>>> benji.say()
"Woof!"
>>> typeof benji.__proto__.say
"function"
>>> typeof benji.__proto__.paws
"undefned"
發現仍舊是舊的prototype,我們新賦值的prototype沒有起到任何作用
現在我們在實例化一個Dog
>>> var lucy = new Dog();
>>> lucy.say()
TypeError: lucy.say is not a function TypeError: lucy.say is not a function
>>> lucy.paws
4
>>> typeof lucy.__proto__.say
"undefned"
>>> typeof lucy.__proto__.paws
"number"
你會發現:
>>> lucy.constructor
Object()
>>> benji.constructor
Dog()
>>> typeof lucy.constructor.prototype.paws
"undefned"
>>> typeof benji.constructor.prototype.paws
"number"
很有趣吧,難道你覺得我很無聊?
其實解決這個問題的方法如下:
>>> Dog.prototype = {paws: 4, hair: true};
>>> Dog.prototype.constructor = Dog;
所以,每當你重寫了prototype,最好重置constructor屬性
如果你問我爲什麼,我不知道.
現在你已經有了足夠的javascript知識,下一篇文章將正式開始進入javascript的面向對象世界。
prototype是functions對象的屬性,也是在javascript中實現繼承的面向對象機制的關鍵,所以有必要弄懂prototype屬性。
首先看看一個普通對象的prototype屬性是什麼:
>>> typeof foo.prototype
"object"
看來所有對象最終都是繼承object的,這和java等語言一樣。
通過prototype可以給function加上函數和屬性。
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
};
或者,用下面這種寫法:
Gadget.prototype = {
price: 100,
rating: 3,
getInfo: function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
}
};
使用prototype增加屬性,該屬性是不會拷貝到每個function實例的.這個表示,你可以修改一個function實例的prototype屬性,這個修改會作用到所有實例上.這有點類似java中的類的static成員變量。
接下來看一個實例,讓你理解js engine在查找prototype屬性的方法:
function Gadget(name) {
this.name = name;
}
Gadget.prototype.name = 'foo';
>>> var toy = new Gadget('camera');
>>> toy.name;
"camera"
>>> delete toy.name;
true
>>> toy.name;
"foo"
如果訪問的是prototype 屬性,js 回找不到,然後會找到constructor的prototype。所以在delete後,第二次調用name返回的是“foo”
那麼如何遍歷得到一個對象的prototype屬性呢?可以這樣:
for (var prop in newtoy) {
console.log(prop + ' = ' + newtoy[prop]);
}
如果你想區分prototype屬性,可以這樣寫:
如果你想區分,可以使用:
>>> newtoy.hasOwnProperty('name')
true
>>> newtoy.hasOwnProperty('price')
false
或者合在一起:
for (var prop in newtoy) {
if (newtoy.hasOwnProperty(prop)) {
console.log(prop + '=' + newtoy[prop]);
}
}
每個對象還有isPrototypeOf方法,作用如下:
var monkey = {
hair: true,
feeds: 'bananas',
breathes: 'air'
};
function Human(name) {
this.name = name;
}
Human.prototype = monkey;
>>> var george = new Human('George');
>>> monkey.isPrototypeOf(george)
true
這個是不是讓你想到繼承。在之後的文章裏我會詳細講解繼承部分。
最後介紹一個很有趣的東西,看看下面的代碼:
>>> function Dog(){this.tail = true;}
>>> var benji = new Dog();
>>> var rusty = new Dog();
>>> Dog.prototype.say = function(){return 'Woof!';}
>>> benji.say();
"Woof!"
>>> benji.constructor;
Dog()
現在一切都很正常。
但是我們在做一點試驗
>>> benji.constructor.prototype.constructor
Dog()
現在讓我們覆蓋prototype
>>> Dog.prototype = {paws: 4, hair: true};
然後調用試試
>>> typeof benji.paws
"undefned"
>>> benji.say()
"Woof!"
>>> typeof benji.__proto__.say
"function"
>>> typeof benji.__proto__.paws
"undefned"
發現仍舊是舊的prototype,我們新賦值的prototype沒有起到任何作用
現在我們在實例化一個Dog
>>> var lucy = new Dog();
>>> lucy.say()
TypeError: lucy.say is not a function TypeError: lucy.say is not a function
>>> lucy.paws
4
>>> typeof lucy.__proto__.say
"undefned"
>>> typeof lucy.__proto__.paws
"number"
你會發現:
>>> lucy.constructor
Object()
>>> benji.constructor
Dog()
>>> typeof lucy.constructor.prototype.paws
"undefned"
>>> typeof benji.constructor.prototype.paws
"number"
很有趣吧,難道你覺得我很無聊?
其實解決這個問題的方法如下:
>>> Dog.prototype = {paws: 4, hair: true};
>>> Dog.prototype.constructor = Dog;
所以,每當你重寫了prototype,最好重置constructor屬性
如果你問我爲什麼,我不知道.
現在你已經有了足夠的javascript知識,下一篇文章將正式開始進入javascript的面向對象世界。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.