本文详细解析 JavaScript 中原型对象与构造函数的关系,阐述原型属性的共享机制及重写 constructor 的影响。通过代码示例说明原型链的查找规则,并演示如何利用 new A() 和 A.call(this) 实现函数间的继承,确保子类保留父类特性及正确的 constructor 指向。
function A(x)
{
this.x = x;
}
alert(A.prototype);
alert(A.prototype.constructor);
原型对象与构造函数关系
从执行结果可知,原型对象由函数的构造函数创建,其拥有的属性可被所有实例共享。初始状态下,原型对象指向一个 Object 对象,并定义了一个 constructor 属性,该属性指向定义该原型对象的构造函数本身。参考以下代码片段。
function A(x)
{
A.prototype.x = x;
}
var obj = new A(10);
alert(obj.x);
alert(obj.constructor);
由于原型对象的所有属性可被构造函数创建的实例共享,因此创建的对象可以访问这里的 constructor 属性。同时,obj 对应的是原型对象(prototype)所创建出来的一个实例。那么,重写 constructor 属性会产生什么结果呢?
function A(x)
{
A.prototype.x = x;
}
var objA = new A(10);
objA.constructor = function(x){ alert("重写obj的constructor属性");this.x = 20 };
objA.constructor();
alert(objA.x);
var objB = new A(10);
alert(objB.x);
原型链查找规则
根据执行结果,首先弹出“重写obj的constructor属性”,接着弹出 20,最后弹出 10。可见,在重写 objA 的 constructor 属性后,objB 并未受到影响。因此,无论在一个对象中加入或修改多少属性,都不影响其原型对象中属性的本来面目。这解释了 JavaScript 的设计逻辑:一个对象的行为不应影响其他对象,否则会造成混乱。总结上述代码规则:1. 调用对象属性时,首先检查该对象自身定义的属性,若存在则调用。2. 若自身属性不存在,则调用其构造函数所定义的原型对象引用。基于此规则,形成了 JavaScript 中的原型链,进而可以定义继承关系。
function A(x)
{
A.prototype.x = x;
}
function B(x,y)
{
B.prototype.y = y;
A.call(this,x);
}
函数继承实现
这段代码展示了两个函数,B 函数继承自 A 函数。A.call(this.x) 表示将 B 的对象 this 传递到 A 函数中执行。为了使由 B 函数构造出的对象包含 A 函数的所有特性,需要添加相关代码。
具体代码如下:
B.prototype = new A();
alert(B.prototype.constructor); 首先指定 B 的原型为 A,因此 B 函数继承了 A 函数的特性。根据弹出结果,其 constructor 指向的是 A 函数,这是否意味着 B 函数的特性丢失?因此,需要再添加一行代码,最后给出完整的整合代码。
function A(x)
{
A.prototype.x = x;
A.prototype.ShowA = function(){ alert("A的Show方法!"); };
}
function B(x,y)
{
B.prototype.y = y;
A.call(this,x);
B.prototype.ShowB = function(){ alert("B的Show方法!"); };
}
B.prototype = new A();
B.prototype.constructor = B;
var obj = new B(10,5);
alert(obj.x);
alert(obj.y);
obj.ShowA();
obj.ShowB();
若有疑问或不正之处,欢迎提出指正和讨论。