本文主要介绍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的面向对象世界。