“原型”是在对象中发挥作用的东西。
在 Javascript 中,一切都是对象。每个对象都有一个种类,因此继承了那个种类的prototype。
例如,取一个简单的数组:var a = []。您可以使用它进行操作,例如a.push(10)。这个push 方法从何而来?来自Array对象的原型,即a。
您可以将自己的方法添加到Array 对象,只需在prototype 对象中定义它们即可。例如:
Array.prototype.sortNum = function() {this.sort(function(a, b) {return a - b});};
通过这种方式,您可以使用 all 数组执行类似 a.sortNum() 的操作,甚至是在定义 sortNum 方法之前创建的数组。
(注意:出于兼容性原因,通常不建议扩展原生对象的原型,如Arrays。但这个特殊的例子通常是一个受欢迎的补充,以及像map和forEach这样的规范化方法对于旧版浏览器。)
(只是永远不会扩展Object.prototype!除非您不想弄乱for...in 语句、in 运算符和这类情况。)
如果您想定义自己的类,就像名称 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"
您也可以在 prototypes 中定义更多的函数:
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
当您改为定义MyConstructor.age = 30 时,您实际上是在定义函数 MyConstructor 的成员,因此mc.age 将是未定义的。 MyConstructor 的每个实例都继承了MyConstructor.prototype 中定义的方法和成员,而不是函数MyConstructor 的方法和成员。
其实还有很多话要说。对象可以是另一个类的子类,因此也继承了超类的prototype。例如,document.body 是HTMLBodyElement 的一个实例,它是HTMLElement 的子类,Element 的子类等等,直到你得到Object 作为最上面的超类。所以,document.body继承了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