本文详细解析JavaScript中对象的原型机制,区分隐式原型(__proto__)与显式原型(prototype)。通过String.prototype.trim示例说明如何扩展内置对象,并阐述原型属性在实例间共享方法与节省内存的原理。重点分析动态修改原型对已创建实例的影响,指出直接赋值原型对象会切断原有继承链,而仅添加属性则可立即生效。
JavaScript 原型基础与访问方式
每个对象都包含一个隐藏的属性,用于指向其构造函数(父对象)的原型,这被称为父原型或隐式原型,对象由此继承属性和方法。对于函数对象,除了指向父原型的引用外,还存在一个显式的原型引用。通常情况下,对象的父原型无法直接访问,但函数对象的显式原型可以通过 FunctionName.prototype 进行访问。在 Firefox 浏览器中,可以通过对象的 __proto__ 属性来访问父原型。
该原型属性本身是一个 Object 类型的对象,因此可以向其中添加任意属性和方法,供实例对象继承使用。
例如,String 类型对象的原型为 String.prototype。若需为 String 类型对象添加自定义方法,可参考以下实现(以添加类似 VBScript 中的 trim 方法为例)。
代码如下:
String.prototype.trim=function(){
return this.replace(/^\s*|\s*$/g,"")
}
// " jiangsk540 ".trim();//return "jiagnsk540" 原型的共享机制与实例化
原型除了提供上述特性外,还提供了一组同类实例对象共享属性和方法的机制。这类似于静态属性或静态函数,无论通过构造函数创建了多少个实例对象,在原型上定义的属性和方法仅定义一次,所有实例对象共享使用这一个属性或方法,但这与 C++ 或 Java 中的静态属性或静态函数概念并不完全相同。
代码如下:
function Class1(name){
this.name = name;
}
Class1.prototype.show=function(){
alert("name="+this.name);
}
var m1 = new Class1("jiangsk540");
var m2 = new Class1("毛狮子");
alert(m1.show===m2.show);//显示 true 动态修改原型对已创建实例的影响
动态向构造函数原型添加的属性或方法,即可被先前建立的实例对象立即调用。
例如:
代码如下:
function Class1(name){
this.name = name;
}
Class1.prototype.show=function(){
alert("name="+this.name);
}
var m1 = new Class1("jiangsk540");
Class1.prototype.say=function(){
alert("Hi");
}
m1.say()//调用成功
/*
注意:只有为构造函数的原型添加的属性或方法,才能被已经创建的对象立即调用。
如果是改变构造函数原型的引用,那么就不能被已经创建的对象立即调用。
*/
Class1.prototype={newP:"jiangsk540"};
alert(m1.newP)//undefined