深入理解JavaScript原型与继承机制

作者:木棉

时间:2026-10-30

浏览:176

本文深入解析JavaScript中的原型与继承机制。通过实例分析instanceof运算符的判断逻辑,区分函数对象与普通对象的prototype与__proto__属性差异,梳理原型链的指向关系,并展示如何利用prototype属性实现实例间的属性共享与继承。

文章目录

引言:对原型与继承的思考

近期在阅读某位开发者编写的JavaScript类库时,我对JS中的原型及继承机制产生了新的思考。尽管此前曾接触过相关概念,但理解始终不够透彻。近日利用空闲时间重新梳理了这一部分知识,发现其中仍有不少值得探讨之处,思路尚显杂乱,特此整理分享。

instanceof运算符的原理

一、instanceof运算符

JavaScript提供了instanceof运算符,这是一个二元运算符,语法为instanceA instanceof A,返回布尔值。其核心作用是判断instanceA是否为A的实例。从实质上看,它是在检测A.prototype是否严格等于instanceA.__proto__,例如:


function f2(){
  var f=function(){}
  var test=new f();
  console.log(test instanceof f);//true
  console.log((f.prototype===test.__proto__));//true
}

上述两处打印结果均为true。这表明test确实是f的一个实例;同时,test的__proto__属性指向了f的prototype对象。这意味着f的prototype属性本身是一个对象,且该对象是f的一个实例。

JavaScript对象分类:函数对象与普通对象

二、JavaScript中的对象分类

在JavaScript中,万物皆对象。对象主要分为函数对象和普通对象两类。我们日常常用的函数实际上属于函数对象,例如:


//函数对象
  var f=function(){}
  var f2=new Function('str','console.log(str)')
  function f3(){}
  //普通对象
  var o=new Object();
  var o2={}
  var o3=new f()

从上述代码可以看出,f、f2、f3属于函数对象,而o、o2、o3属于普通对象。

函数对象与普通对象的主要区别在于:

所有通过new Function()方式创建的对象均属于函数对象。无论是f还是f3这两种定义方式,最终在底层也是通过new Function()创建的;

在定义对象时,对象内部包含一些预定义属性,如prototype和__proto__。其中,prototype属性仅函数对象拥有,而__proto__属性则对所有对象都存在。因此,可以通过检查对象的__proto__属性来判断其类型,例如:


//函数对象
  var f=function(){}
  //普通对象
  var o=new Object();
  console.log(f.prototype);//Object {}
  console.log(o.prototype);//undefined

由上述结果可知,函数对象存在prototype属性,而普通对象的prototype属性则为undefined(未定义)。

原型链的构建与指向

三、原型链机制

前文提到,所有对象都拥有__proto__属性,该属性指向创建它的函数对象的原型对象prototype。我们将这种通过__proto__属性串联起来的链条称为原型链,如下所示:

引言:对原型与继承的思考

以上图为例,以person为例说明原型链的结构:


var person=function(){}
var person1=new person();

1、person是一个函数对象,person1是person的一个实例;

2、person1的__proto__属性指向person的原型对象person.prototype;

3、由于person的原型对象person.prototype本身也是一个对象,它同样拥有__proto__属性,该属性指向Object的原型对象Object.prototype;

4、Object的原型对象Object.prototype也是一个对象,它也有__proto__属性,该属性的原型对象为null。

利用原型实现继承

四、实现继承的方式

在JavaScript中,我们通常会定义一个函数对象,例如:


var person=function(){}

上述代码定义了一个没有任何属性的空函数对象。由于它是对象,因此可以为其添加属性,例如:


var person=function(){}
person.name1='js'
console.log(person.name1)//js

上述代码为person新增了一个name属性,并赋值为'js',且可以成功打印出name属性的值。 然而,当我们创建person的一个实例person1时,如下所示:


var person= function(){};
  person.name1= 122;
  console.log(person.name1);
  var person1=new person();
  console.log(person1.name1);//undefined

可以看到,person1并没有name1这个属性。那么,如何确保person的实例也能拥有name1属性呢?


var person= function(){};
  person.name1= 122;
  //使用prototype对象为对象添加属性,这样所以的实例都会有此属性
  person.prototype.name1='12';
  console.log(person.name1);
  var person1=new person();
  console.log(person1.name1);//12

如上所示,使用了person.prototype.name1='12'。这样,所有实例都将拥有name1属性。通过这种方式添加的属性,在生成实例时会被视为实例的共有属性。

以上关于JavaScript原型与继承的探讨即为全部内容,希望能为大家提供参考,也希望大家多多支持本站。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章