图解JavaScript原型(prototype)与原型链机制

作者:异步漫步时间:2026-10-22 07:43:05浏览:651

本文深入解析JavaScript中原型(prototype)与原型链的核心机制。通过图解方式说明构造函数、原型对象与实例之间的__proto__指向关系,阐述属性与方法查找的就近原则,并揭示原型链如何使自定义对象继承Object内置方法,实现实例间的属性共享。

原型与原型链基础概念

利用原型方式,我们解决了多个实例间方法共享的问题。接下来,我们将深入剖析原型(prototype)与原型链的具体运作机制。


function CreateObj(uName) {
   this.userName = uName;
  }
  CreateObj.prototype.showUserName = function(){
   return this.userName;
  }
  var obj1 = new CreateObj('ghostwu');
  var obj2 = new CreateObj('卫庄');

原型与原型链基础概念

首先,每个函数都拥有一个名为 prototype 的属性。该属性是一个指针,指向构造函数的原型对象(例如 CreateObj.prototype),如图中第1条绿色箭头所示。

其次,默认情况下,所有原型对象都会自动获得一个 constructor 属性。该属性的作用在于指向定义该 prototype 属性的函数,如图中第2条绿色箭头所示。

第三,所有通过构造函数使用 new 创建的实例(包括原型对象如 CreateObj.prototype,尽管图中暂未画出),都包含一个隐式原型属性 __proto__。该指针指向实例所属构造函数的原型对象。

如图中第3条和第4条箭头所示,obj1 的构造函数是 CreateObj,其原型对象为 CreateObj.prototype;obj2 同理。因此:

obj1.__proto__ === CreateObj.prototype //true

obj2.__proto__ === CreateObj.prototype //true

第四,在构造函数内部通过 this 赋值的属性和方法,在绘制对象模型时,应将其画在具体的实例对象上。例如 userName 是赋予对象的属性,因此 obj1 和 obj2 这两个实例对象上都会存在 userName 属性。

第五,定义在原型对象上的方法或属性,在绘制模型时应将其画在原型对象上。例如:


CreateObj.prototype.showUserName = function(){
return this.userName;
}

showUserName 方法应当绘制在图中的 CreateObj.prototype 上。

第六,当对象访问属性或方法时,遵循“就近原则”,具体规则如下:

如果实例上存在该属性或方法,则直接使用实例上的值。

如果实例上不存在该属性或方法,则沿着实例的 __proto__ 指针指向的原型对象继续向上查找;若仍找不到,则返回 undefined。


console.log( obj1.showUserName() ); //ghostwu
console.log( obj2.showUserName() ); //卫庄

在 obj1 和 obj2 上并不存在 showUserName 方法,因此会顺着 __proto__ 查找至 CreateObj.prototype 原型对象上的 showUserName 方法。

如果将 CreateObj.prototype 原型对象上的 showUserName 方法注释掉,那么 obj1.showUserName 和 obj2.showUserName 将会报错。


// CreateObj.prototype.showUserName = function(){
// return this.userName;
// }

function CreateObj(uName) {
   this.userName = uName;
   this.showUserName = function(){
    return '100';
   }
  }
  CreateObj.prototype.showUserName = function(){
   return this.userName;
  }

  var obj1 = new CreateObj('ghostwu');
  var obj2 = new CreateObj('卫庄');

  console.log( obj1.showUserName() ); //100
  console.log( obj2.showUserName() ); //100

如果在构造函数内部为 this 添加一个 showUserName 方法,那么 obj1 和 obj2 将直接调用 this 上的方法。因为这两个方法被绘制在实例上,所以:


console.log( obj1.showUserName === obj2.showUserName ); //false

现在,你应该能明白,将属性和方法写在构造函数的原型对象(prototype)上后,能够实现多个实例属性和方法共享的原理了吧。

原型链的构成与查找机制

什么是原型链?

前文提到,所有实例(包括原型对象)都有一个隐式原型 __proto__。那么,CreateObj.prototype 这个原型对象的 __proto__ 指向哪里呢?


function CreateObj(uName) {
   this.userName = uName;
   this.showUserName = function () {
    return '100';
   }
  }
  CreateObj.prototype.showUserName = function () {
   return this.userName;
  }

  console.log( CreateObj.prototype.__proto__ ); //指向Object.prototype
  console.log( CreateObj.prototype.__proto__ === Object.prototype ); //true

原型与原型链基础概念

CreateObj.prototype.__proto__ 指向的是 Object.prototype,通过全等运算符(===)测试结果为 true。

Object.prototype.__proto__ 指向的是 NULL。

这就是原型链,它通过隐式原型将各个构造函数层层串联起来。通过上述图示,我们可以理解为什么自定义对象能够调用 toString、valueOf 等方法。

因为所有对象最终都继承自 Object。

以上这篇[js高手之路]图解javascript的原型(prototype)对象,原型链实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。

作者最新文章