Javascript中的原型关键字
什么是prototype
属性,为什么它是必要的? 到目前为止,我已经知道,这为公众提供了更多内在的,私人的对象prototype
; 那是对的吗?
另外,下面的陈述有什么区别?
MyConstructor.age = 30; MyConstructor.prototype.age = 30;
总之,我需要更好地了解关键字prototype
。
谢谢
“原型”是在对象中起作用的东西。
在Javascript中,一切都是一个对象。 每个对象都有一种types,从而inheritance了这种types的prototype
。
例如,取一个简单的数组: var a = []
。 你可以用它来操作,比如a.push(10)
。 push
方法从哪里来? 从Array
对象的原型来看,哪a
是。
您可以将自己的方法添加到Array
对象,只需在prototype
对象中定义它们即可。 例如:
Array.prototype.sortNum = function() {this.sort(function(a, b) {return a - b});};
通过这种方式,您可以对所有数组执行类似于a.sortNum()
,甚至可以在定义sortNum
方法之前创build数组。
(注意:出于兼容性原因,通常不build议扩展像Array
这样的本地对象的原型,但是这个特殊的例子通常是一个值得欢迎的例子,同时也为像老版本的浏览器的map
和forEach
这样的标准化方法。
(只要永远不要扩展Object.prototype
!除非你不在乎在for...in
声明中, in
运算符和这些types的情况下搞砸了。)
如果你想定义你自己的类,比如MyConstructor
的名字,你必须定义它的prototype
来定义这个类的所有实例的方法:
function MyConstructor(name) {this.name = name}; MyConstructor.prototype = { print: function() {return this.name;} }; var mc = new MyConstructor("foo"); alert(mc.print()); // alerts "foo"
您也可以在prototype
定义更多的function:
MyConstructor.prototype.age = 30; alert(mc.age); // alerts 30
当你这样做的时候要注意定义“默认”对象值,因为改变它可能会导致该类的所有实例发生变化。
但是这与Object.defineProperty
方便:
Object.defineProperty(MyConstructor.prototype, "wholeString", { get: function() {return this.name + "=" + this.age;}, set: function(v) {this.name = v.substring(3);} }); alert(mc.wholeString); // alerts "foo = 30"
(不幸的是,IE <9只允许这个DOM对象…)
当你定义MyConstructor.age = 30
,你实际上在做的是定义MyConstructor
函数的一个成员,所以mc.age
将是未定义的。 MyConstructor
每个实例都inheritanceMyConstructor.prototype
定义的方法和成员,而不是函数MyConstructor
的方法和成员。
实际上还有很多要说的。 对象可以是另一个类的子类,因此也inheritance了超类的prototype
。 例如, document.body
是HTMLBodyElement
一个实例,它是HTMLElement
一个子类,它是Element
一个子类,等等,直到你把Object
作为最上层的超类。 所以, document.body
inheritance了HTMLBodyElement
, HTMLElement
, Element
和Object
原型中定义的所有方法。 这被称为原型链。
对自定义对象做同样的事情有点棘手:
function Class() {}; Class.prototype.foo = function() {alert("foo");}; function Subclass() {}; Subclass.prototype = new Class(); Subclass.prototype.bar = function() {alert("bar");}; var a = new Class(), b = new Subclass(); a.foo(); // alerts"foo" a.bar(); // throws an error b.foo(); // alerts "foo" b.bar(); // alerts "bar" a instanceof Class; // true a instanceof Subclass; // false b instanceof Class; // true b instanceof Subclass; // true
在JavaScript中,函数对象具有内置的.prototype
属性。 这个属性的值是一个对象。 如果该函数被用作构造函数,那么结果实例将inheritance该“原型”对象。
例:
var Dog = function () {}; // the constructor function Dog.prototype.bark = function () {}; // adding a method to Dog.prototype var dog1 = new Dog; // creating a new instance dog1.bark(); // the instance inherits the "bark" method from Dog.prototype
请注意,函数对象的.prototype
属性与[[Prototype]]
内部属性不同。 所有对象都包含后者。 这是一个对象原型的内部引用。 (在上面的例子中, dog1
对象的[[Prototype]]
指的是Dog.prototype
。)另一方面,只有函数对象具有内置的.prototype
属性(这是有道理的,因为只有函数对象可以用作构造函数)。
var foo = function () {}; foo.bar = 5; foo.prototype.foobar = 10; var x = new foo(); x.bar; // undefined x.foobar; // 10
编辑:另外,你可以做
foo.prototype.foobar = 20; x.foobar; // 20