原型链详解

什么是原型链

原型链就是顺着__proto__所在的一条链子,这样说可能不是很好理解,下面来看例子你就会理解。

需要了解

1.a.__proto__a.prototype都称做为a的原型。
2.Object.prototype是原型链的顶端。
3.如果 a是由b实例化出来的,则有关系a.__proto__ === b.prototype,所以a.__proto__的地址和b.prototype指向的地址是一样的,即他们使用的是同一个对象。

原型链解读

先以函数实例的原型链为例子为大家讲解

function A(){}
const a=new A()
console.log(a.__proto__===A.prototype)   // true,这里是根据上面 '需要了解'处可以推断
console.log(A.prototype.__proto__===Object.prototype)   
// true,这里可以通过打印 A ,然后展开看到 A 就能看到该关系

知道以上关系后,可以得出原型链如下:
在这里插入图片描述
再以数组的原型链为例

const arr=[]
console.log(arr.__proto__===Array.prototype)  //true,根据上面 '需要了解'处可以推断
console.log(Array.prototype.__proto__===Object.prototype)  
// true,打印 Array,然后展开Array就能看到该关系

知道以上关系后,可以得出原型链如下:
在这里插入图片描述
其它的原型链如:函数、对象、正则、日期的原型链和上面的基本一致。

原型链的作用

首先你需要只知道的是,处在原型上的对象,是可以顺着自己所在原型链向上找,然后可以使用上面的方法或者属性。主要作用就是减少内存消耗,提高代码的复用率。看看下面示例你就会明白

function A(){}
A.prototype.f1=()=>{console.log('f1')}
A.prototype.f2=()=>{console.log('f2')}
A.prototype.f3=()=>{console.log('f3')}

const a1=new A()
const a2=new A()
const a3=new A()

a1.f1()  // f1
a2.f1()  // f1
a3.f1()  // f1

把一些公共的方法添加到原型上,这样我们实例化的每个对象就都可以使用这些这些原型上的方法了。如果我们不把方法添加到原型上,而现在需求是需要每个实例都能使用上面的这些方法,那我们只能将这些方法都添加到实例上例:a1.f1=f1。如果我们把这些方法添加到原型上,实例使用时,只需要往原型上找就行,而且所有实例使用的同一个原型。对比一看,是不是省了很多内存开销。

合理使用原型

手动在原型上添加某个属性

Object.prototype.a=2

这是第三方库a.js含有如下代码

Object.prototype.a=1

此时引入a.js

const obj={}
console.log(obj.a)   // 1 

此时不是我们期望的结果,所以不要滥用原型,不要在系统的原型上随意添加修改方法

原型的读写相关方法

const user={name:"nb",age:18}

//获取user对象的 __proto__
Object.getPrototypeOf(user) 
// 把user对象的原型修改为{},修改对象的__proto__,只能修改为对象
Object.setPrototypeOf(user,{}) 

原型为什么不能修改为非对象

const obj={}
obj.__proto__=1
console.log(obj.__proto__)  //打印后依然是一个对象
/*
<get __proto__()>: function __proto__()
<set __proto__()>: function __proto__()
*/

在打印的对象中可以找到 __proto__ 属性被劫持了,这就是原因。

结尾

看完这篇文章后,你会发现原型链用来是这么的简单。感谢你们的观看,希望这篇文章能给你带来帮助。如果有小伙伴有问题或者疑惑,欢迎提出和分享。

<think>嗯,用户想了解JavaScript中的原型和原型链,我得先理清楚这些概念。首先,原型是什么?根据引用[5],每个函数都有一个prototype属性,指向原型对象,这个对象里的属性和方法可以被所有实例共享。比如Person构造函数,它的prototype添加了name和sayName方法,这样所有实例比如person1和person2都能调用这个方法,而且方法是同一个,节省内存。 接下来原型链呢?引用[2]提到每个对象都有一个内部属性(__proto__)指向原型对象,形成链式结构。比如实例person1的__proto__指向Person.prototype,而Person.prototype本身也是个对象,它的__proto__又指向Object.prototype,这样一层层直到null,形成原型链。当访问对象的属性时,如果自身没有,就会沿着原型链向上查找,直到找到或到顶层。 继承方面,引用[3]和[4]都提到基于原型的继承。比如,通过将子类的原型指向父类的实例,子类就能继承父类的属性和方法。但要注意constructor属性的修正,避免指向错误。此外,引用中还提到new操作符的原理,创建一个新对象,并将其原型链接到构造函数的prototype,然后执行构造函数绑定this,最后返回对象。 可能用户需要知道原型链的实际应用,比如方法共享、继承实现,以及如何避免常见问题,比如修改原型影响所有实例。此外,引用中提到的instanceof和hasOwnProperty方法也很重要,用于判断类型和属性来源。 用户的问题可能涉及如何实现继承,原型链查找机制,或者为什么方法要放在prototype上。需要结合例子详细解释,比如构造函数、实例、原型之间的关系图,以及原型链的终点是null。还要注意解释__proto__和prototype的区别,前者是实例的属性,后者是构造函数的属性。 可能还需要提到ES6的class语法糖,背后还是基于原型的机制,这样用户理解现代JS写法时不会混淆。同时,注意性能方面的考虑,比如过长原型链会影响查找速度,但通常影响不大。 总结回答结构:先介绍原型和原型链的定义,再讲构造函数、实例、原型对象的关系,接着说明原型链如何实现继承,最后讨论相关方法和应用场景。确保引用正确,比如每个引用对应的知识点,比如原型链的形成[^4],共享方法[^5],继承实现[^3]等。</think>### JavaScript原型与原型链解析 #### 一、原型(Prototype) 1. **基本概念** 每个函数在创建时都会自动关联一个`prototype`属性(显式原型),指向一个原型对象。此对象包含可被所有实例共享的属性和方法。例如: ```javascript function Person() {} Person.prototype.name = "Alice"; const p1 = new Person(); console.log(p1.name); // "Alice" ``` 2. **作用与意义** - **共享方法**:避免重复创建函数,节省内存。例如多个实例共享`sayName`方法。 - **继承基础**:通过原型链实现属性和方法的继承。 --- #### 二、原型链(Prototype Chain) 1. **形成机制** - 每个对象都有一个内部属性`[[Prototype]]`(可通过`__proto__`访问,隐式原型),指向其构造函数的`prototype`。 - 当访问对象属性时,若自身不存在,则沿`__proto__`向上查找,直到`Object.prototype.__proto__`(即`null`),形成链式结构[^2][^4]。 $$ \text{实例} \xrightarrow{\_\_proto\_\_} \text{构造函数.prototype} \xrightarrow{\_\_proto\_\_} \text{Object.prototype} \xrightarrow{\_\_proto\_\_} \text{null} $$ 2. **继承示例** ```javascript function Parent() { this.name = "Parent"; } Parent.prototype.say = function() { console.log(this.name); }; function Child() { Parent.call(this); } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; // 修正构造函数指向 const c = new Child(); c.say(); // "Parent"(通过原型链调用) ``` --- #### 三、关键方法与实践 1. **`new`运算符原理** - 创建空对象,链接到构造函数原型。 - 执行构造函数(绑定`this`),返回对象。伪代码实现: ```javascript function myNew(constructor, ...args) { const obj = Object.create(constructor.prototype); const result = constructor.apply(obj, args); return result instanceof Object ? result : obj; } ``` 2. **类型判断与属性检测** - **`instanceof`**:检查对象是否在原型链上。 - **`hasOwnProperty`**:检测属性是否为对象自身所有(非继承)。 --- #### 四、应用场景与注意事项 1. **应用场景** - **共享工具方法**:将公共方法定义在原型上(如`Array.prototype.map`)。 - **实现继承**:通过修改子类原型指向父类实例。 2. **注意事项** - **原型污染**:修改`Object.prototype`会影响所有对象,需谨慎。 - **性能影响**:过长的原型链会增加属性查找时间。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值