继承与原型链--JavaScript

深入解析JavaScript的原型链机制及其实现的继承模型,对比基于类的语言,展示如何通过原型链实现属性查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

JavaScript语言是动态的,本身不提供基于类语言(如Java或C++)的class实现。在ES2015/ES6中引入class关键字,只是JavaScript基于原型的语法糖。

尽管原型继承被认为是JavaScript的弱点之一,但原型继承模型本身比经典模型更强大。列如,在原型模型的基础上构建经典模型相当简单。

当谈到继承时,JavaScript只有一种结构:对象。每个实例对象(object)都有一个指向它的原型对象(prototype)的私有属性_proto_。该原型对象也有一个指向自己的原型对象(prototype)的私有属性_proto_。层层向上直到一个对象的原型对象为null。null因为没有原型,所以作为这个原型链中的最后一个环节。几乎所有JavaScript中的对象都是位于原型链顶端的Object的实例。

基于原型链的继承

继承属性
JavaScript对象是动态的属性"包"(指其自己的属性)。JavaScript对象有一个指向一个原型对象的链。当访问一个对象的属性时,首先在该对象上查找,然后在该对象的原型上查找,紧接着在该对象的原型的原型上,依次层层向上搜索,直到找到一个名字匹配的属性或到达该原型链的末尾。

注意

遵循ECMAScript标准,someObject.[[Prototype]]符号是用于指向someObject的原型。
从ECMAScript6开始,[[Prototype]]可以通过Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。
这个等同于JavaScript的非标准但许多浏览器实现的属性_proto_。
Object.prototype属性表示Object的原型对象。被构造函数创建的实例对象的[[prototype]]指向func的prototype属性。两者不要混淆。

接下来演示当尝试访问属性时会发生什么

let f = function () {
   this.a = 1;
   this.b = 2;
}
let o = new f(); // {a:1,b:2}
// 在f函数的原型上定义属性
f.prototype.b = 3;
f.prototype.c = 4;

// 不要在f函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
// o.[[Prototype]] 有属性 b 和 c(其实就是o._proto_或者o.constructor.prototype)
// o.[[Prototype]].[[Prototype]] 是 Object.prototype.
// 最后o.[[Prototype]].[[Prototype]].[[Prototype]]是null
// 这就是原型链的末尾,即 null,根据定义,null 没有[[Prototype]].
// 综上,整个原型链如下:{a:1,b:2} ---> {b:3,c:4} ---> Object.prototype ---> null

console.log(o.a); //1
// a是o的自身属性吗?是的,该属性的值为1
console.log(o.b); //2
// b是o的自身属性吗?是的,该属性的值为2
// 原型上也有一个'b'属性,但是它不会被访问到。这种情况称为"属性遮蔽"
console.log(o.c); //4
// c是o的自身属性吗?不是,那看看原型上有没有
// c是o.[[Prototype]]的属性吗?是的,该属性的值为4
console.log(o.d); // undefined
// d是o的自身属性吗?不是,那看看原型上有没有
// d是o.[[Prototype]]的属性吗?不是,那看看它的原型上有没有
// o.[[Prototype]].[[Prototype]] 为 null, 停止搜索
// 没有d属性,返回undefined   
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值