深入理解 JavaScript 原型(prototype)与原型链

作者:代码拾荒

时间:2026-10-29

浏览:264

本文深入解析 JavaScript 中 prototype 的核心机制,区分类方法、对象方法与原型方法。通过实验阐明 prototype 实现的是对象克隆而非传统继承,并演示如何利用 call 方法在实例间调用原型方法,帮助开发者掌握原型链的工作原理。

文章目录

JavaScript prototype 机制解析

JavaScript 中的 prototype(原型)是许多开发者感到困惑的核心概念之一。

为了清晰阐述这一概念,本文将基于以下几个关键知识点展开讨论。

1. 原型设计模式概述 在 .NET 等语言中,可以通过 clone() 方法实现原型模式。

原型模式的核心思想是:若已存在一个类 A,现在需要创建一个以 A 为原型的类 B 并进行扩展,我们将 A 称为 B 的原型。

2. JavaScript 方法的分类: a. 类方法(静态方法)

b. 对象方法(实例方法)

c. 原型方法

具体示例如下:


function People(name){ 

  //对象属性
  this.name=name; 

  //对象方法 
  this.Introduce=function(){

     alert("My name is "+this.name); 

  }

}
​//类静态方法

​People.Run=function(){ 

  alert("I can run");

}

​//原型方法

​People.prototype.IntroduceChinese=function(){ 

 alert("我的名字是"+this.name);

} 

​//测试

​var p1=new People("Windking");

p1.Introduce();//调用对象方法

People.Run();//调用静态方法

p1.IntroduceChinese(); //调用原型方法

3. 使用 obj1.func.call(obj) 方法 该语法的作用是将 obj 视为 obj1 的上下文来调用 func 方法。原本调用的是 obj1 的 func,但通过传入 obj 改变了上下文对象,从而使得 obj 能够调用 obj1 定义的方法。

接下来,我们将逐一解决上述问题。

prototype 的具体含义是什么?

JavaScript 中的每个对象都拥有 prototype 属性。该属性的作用是返回对象类型原型的引用。

例如:A.prototype = new B();

理解 prototype 时,不应将其与传统的“继承”混淆。A 的 prototype 是 B 的一个实例,这可以理解为 A 将 B 中的方法和属性克隆了一遍,从而可以使用 B 的方法和属性。这里强调的是“克隆”而非“继承”。值得注意的是,可能出现 A 的 prototype 是 B 的实例,同时 B 的 prototype 也是 A 的实例的情况。

原型克隆与同名方法覆盖实验

首先看一个实验示例:


function baseClass(){

  this.showMsg = function(){

    alert("baseClass::showMsg");  

  }

}

function extendClass(){

}

extendClass.prototype = new baseClass();

var instance = new extendClass();

instance.showMsg(); // 显示baseClass:showMsg

我们首先定义了 baseClass 类,接着定义 extendClass。我们的策略是以 baseClass 的一个实例为原型,克隆出 extendClass,使其同时包含 showMsg 这个对象方法。

语句 extendClass.prototype = new baseClass() 可以解读为:extendClass 是以 baseClass 的一个实例为原型克隆创建的。

那么,如果 extendClass 中本身包含一个与 baseClass 同名的方法,会发生什么?

以下是扩展实验 2:


function baseClass(){

  this.showMsg = function(){

    alert("baseClass::showMsg");  

  }

}

function extendClass(){

  this.showMsg =function (){

    alert("extendClass::showMsg");

  }

}

extendClass.prototype = new baseClass();

var instance = new extendClass();

instance.showMsg();//显示extendClass::showMsg

实验证明:函数运行时,会优先在本体(实例自身)中查找函数;如果找到则运行;如果找不到,则去 prototype 中查找。或者可以理解为:prototype 不会覆盖或克隆同名函数。

利用 call 调用原型方法

由此引出一个新问题:

如果我想使用 extendClass 的一个实例 instance 调用 baseClass 的对象方法 showMsg,该怎么做?

答案是可以使用 call 方法:


extendClass.prototype = new baseClass();

var instance = new extendClass();

var baseinstance = new baseClass();

baseinstance.showMsg.call(instance);//显示baseClass::showMsg

语句 baseinstance.showMsg.call(instance) 可以解读为:“将 instance 当作 baseinstance 来调用,执行它的对象方法 showMsg”。

这里可能有人疑问,为什么不用 baseClass.showMsg.call(instance)?

这涉及对象方法与类方法的区别。我们想要调用的是 baseClass 的对象方法,而非静态方法。

最后,如果下面的代码能够理解清晰,那么本文所阐述的内容就已经被掌握了:


function baseClass(){

  this.showMsg = function(){

    alert("baseClass::showMsg");  

  }

  

  this.baseShowMsg = function() {

    alert("baseClass::baseShowMsg");

  }

}

baseClass.showMsg = function(){

  alert("baseClass::showMsg static");

}

function extendClass(){

  this.showMsg =function (){

    alert("extendClass::showMsg");

  }

}

extendClass.showMsg = function(){

  alert("extendClass::showMsg static")

}

extendClass.prototype = new baseClass();

var instance = new extendClass();

instance.showMsg(); //显示extendClass::showMsg

instance.baseShowMsg(); //显示baseClass::baseShowMsg

instance.showMsg(); //显示extendClass::showMsg

baseClass.showMsg.call(instance);//显示baseClass::showMsg static

var baseinstance = new baseClass();

baseinstance.showMsg.call(instance);//显示baseClass::showMsg

以上就是关于 JavaScript 中 prototype 的深入学习,后续还将更新相关文章,希望大家继续关注。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章