深入理解JavaScript原型与继承机制
本文深入解析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原型与继承的探讨即为全部内容,希望能为大家提供参考,也希望大家多多支持本站。
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
