深入理解JavaScript原型:Prototype属性与继承机制

作者:纸飞机

时间:2026-10-29

浏览:633

本文深入解析JavaScript基于原型的面向对象特性,详细阐述prototype属性、原型对象与构造函数之间的指向关系。通过代码示例说明原型继承的工作原理,对比实例属性与原型属性的区别,并介绍如何结合构造函数与Prototype定义类的字段和行为,实现对象实例间的属性与方法共享。

文章目录

JavaScript的原型基础

JavaScript是一种面向对象编程语言,但其核心机制基于原型(Prototype),而非传统的基于类的语言。在JavaScript中,类与对象的概念界限相对模糊,两者之间没有明显的区分。

Prototype属性与对象关系

理解prototype的概念是掌握JavaScript的关键。

在JavaScript中,通过function定义的对象拥有一个prototype属性。该属性指向一个prototype对象。需要注意的是,prototype属性与prototype对象是两个不同的概念,必须加以区分。在prototype对象内部,包含一个constructor属性,该属性指向constructor对象,而这个constructor对象实际上就是定义该函数的function本身。这一关系可能较为复杂,可以通过伪代码来辅助理解:

原型结构伪代码


var function{
prototype:prototype{
constructor:constructor == function
}
}

原型关系图解

如果上述描述仍难以理解,可以参考图示说明:

JavaScript的原型基础

Prototype的作用与继承机制

接下来探讨prototype的具体作用。

prototype究竟发挥什么作用?通过以下示例进行说明:

原型属性继承示例


function jb51(){
}
jb51.prototype.name = "a";
var test = new jb51();
alert(test.name)//"a";

这里存在一个疑问:明明没有为test对象设置name属性,为何却能获取到值?

这正是prototype发挥的作用。在uw3c中,prototype属性里的name对象,在通过new构造函数创建test对象后,被继承到了test对象的属性中。继续观察后续代码:

属性查找与覆盖机制


var name = "js";
function jb51(name){
alert(this.name);//"css"
}
jb51.prototype.name = "css";
var test = new jb51();
test()

为什么alert输出的值不是“js”?这个过程大致如下:

构造函数调用过程


var test={};
uw3c.call(test);

第一步,系统建立一个新的对象(test)。

第二步,将该对象(test)内置的原型对象设置为构造函数(即uw3c)的prototype属性所引用的那个原型对象。

第三步,将该对象(test)作为this参数调用构造函数(即uw3c),从而完成成员设置等初始化工作。

在第二步中涉及一个新概念:内置的原型对象。请注意,这个内置原型对象与prototype对象并非同一事物。为了区分,此处将其称为inobj。inobj指向函数uw3c的prototype对象。在uw3c的prototype对象中定义的任何属性或函数,都可以直接在test对象中使用,这就是JavaScript中的原型继承机制。

对象创建与实例属性

通常,创建对象的方式如下:

构造函数定义对象


function person(name){
this.sayHi = function(){
alert('hi ' + this.name);
}
this.name = name;
}
var p = new person("dan");
p.sayHi(); 

如上所示,使用new关键字,通过对象(函数也是一种特殊对象)来创建对象实例。

在基于类的语言中,属性或字段通常在类定义阶段就已确定。但在JavaScript中,即使在对象创建之后,仍然可以为类添加字段。

实例属性与原型属性的区别


function animal(){}
var cat = new animal();
cat.color = "green"; 

以上示例中,color字段仅属于当前的cat实例。那么,如果希望所有animal的实例都拥有该字段,该如何操作?

使用Prototype共享属性


--使用Prototype
function animal(){}
animal.prototype.color= "green";
var cat = new animal();
var dog = new animal();
console.log(cat.color);//green
console.log(dog.color);//green 

通过Prototype不仅可以添加字段,还可以添加方法。

通过Prototype添加方法


function animal(){}
animal.prototype.color= "green";
var cat = new animal();
var dog = new animal();
console.log(cat.color);//green
console.log(dog.color);//green
animal.prototype.run = funciton(){
console.log("run");
}
dog.run(); 

由此可见,通过prototype属性,可以在对象创建后改变对象的行为。例如,可以为数组这一特殊对象添加一个方法。

扩展内置对象方法


Array.prototype.remove = function(elem){
var index = this.indexof(elem);
if(index >= 0){
this.splice(index, 1);
}
}
var arr = [1, 2, 3] ;
arr.remove(2); 

除了通过prototype为对象定义属性或方法,还可以通过对象的构造函数来定义类的属性或方法。

构造函数定义方法


function animal(){
this.color = "green";
this.run = function(){
console.log("run");
}
}
var mouse = new animal();
mouse.run(); 

上述做法同样能使所有animal实例共享所有的字段和方法。此外,还有一个优势:可以在构造函数中使用类的局部变量。

构造函数中使用局部变量


function animal(){
var runAlready = false;
this.color = "green";
this.run = funciton(){
if(!runAlreadh){
console.log("start running");
} else {
console.log("already running")
}
}
} 

实际上,更实用的做法是将通过构造函数与通过Prototype定义类的字段和行为相结合。

结合构造函数与Prototype的最佳实践


function animal(){
var runAlready = false;
this.run = function(){
if(!runAlready){
console.log('i am running');
} else {
console.log("i am already running");
}
}
}
animal.prototype.color = '';
animal.prototype.hide = funciton(){
console.log("");
}
var horse = new animal();
horse.run();
horse.hide(); 

Prototype允许我们在创建对象之后改变对象或类的行为,并且通过prototype属性添加的字段或方法,所有对象实例都是共享的。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章