写该系列文章的初衷是“让每位前端工程师掌握高频知识点,为工作助力”。这是前端百题斩的第17斩,希望朋友们关注公众号“执鸢者”,用知识武装自己的头脑。
17.1 基础
在js中,每一个对象都包含一个原型属性,用于关联另一个对象,关联后就能够使用那个对象的属性和方法;对象之间通过原型关联到一起,就好比用一条锁链将一个个对象连接在一起,在与各个对象挂钩后,最终形成了一条原型链。(注意:js中的对象分为函数对象和普通对象,这两类对象均具备__ proto __属性,但是只有函数对象才有prototype属性。)
17.2 原型链流程
下图是网上流传的学习原型链的一幅神图,我们先贴出来一点一点分析。
17.2.1 普通对象
js对象中的一种类型是普通对象,上述图中的一条主线也是根据普通对象来的,下面通过一段代码来演示一下。
const obj = {
a: 10,
b: 20
};
console.log(obj);
console.log(obj.__proto__);
console.log(obj.__proto__.__proto__);
console.log(obj.__proto__.constructor);
console.log(obj.__proto__.constructor.__proto__);
console.log(obj.__proto__.constructor.__proto__.__proto__);
console.log(obj.__proto__.constructor.__proto__.constructor);
console.log(obj.__proto__.constructor.__proto__.constructor.__proto__);
上述的打印结果如下所示,其打印结果与上述普通对象的链路完全一致。
17.2.2 函数对象
js对象中的一种类型是函数对象,上述图中的一条主线也是根据函数对象来的,下面通过一段代码来演示一下。
function fun() {
let a = 12;
}
console.log(fun);
console.log(fun.__proto__);
console.log(fun.__proto__.__proto__);
console.log(fun.__proto__.__proto__.__proto__);
console.log(fun.__proto__.constructor);
console.log(fun.__proto__.constructor.__proto__);
console.log(fun.__proto__.constructor.__proto__.__proto__);
console.log(fun.__proto__.constructor.__proto__.__proto__.__proto__);
上述的打印结果如下所示,其打印结果与上述函数对象的链路完全一致。
17.3 两个机制
上述讲述了原型链的定义及其流程,那么对于其上的属性是按照什么流程查找和修改该的呢?
17.3.1 属性查找机制
当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype,如还是没找到,则输出undefined;
const obj1 = {
a: 10
};
const obj2 = {
b: 20
};
Object.setPrototypeOf(obj2, obj1);
// 由于obj2自身不存在a属性,但是其原型obj1上存在,所以输出其上的值10;
console.log(obj2.a); // 10
// 由于b属性在obj2本身,输出20;
console.log(obj2.b); // 20
// c属性在obj2和其原型上都不存在,则输出undefined。
console.log(obj2.c); // undefined
17.3.2 属性修改机制
只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2;但是这样会造成所有继承于该对象的实例的属性发生改变。
const obj1 = {
a: 10
};
const obj2 = {
b: 20
};
Object.setPrototypeOf(obj2, obj1);
console.log(obj2); // {b: 20}
console.log(obj1); // {a: 10}
obj2.b = 30;
obj2.a = 50;
// 修改b属性生效,修改a属性在其本身添加了a属性
console.log(obj2); // { b: 30, a: 50 }
console.log(obj1); // { a: 10 }
obj2.__proto__.a = 20;
// 直接修改原型上属性生效
console.log(obj1); // { a: 20 }
1.如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~
2.关注公众号执鸢者,领取学习资料,定期为你推送原创深度好文
3.关注公众号进群,里面大佬多多,一起向他们学习
1. 前端百题斩[001]——typeof和instanceof
3. 前端百题斩【003-004】——从基本类型、引用类型到包装对象
6. 前端百题斩【007】——js中必须知道的四种数据类型判断方法
7. 前端百题斩【008-009】——从JavaScript的代码执行过程到函数执行过程
8. 前端百题斩【010】——通俗易懂的JavaScript执行上下文
10. 前端百题斩【012】——js中作用域及作用域链的真面目
12. 前端百题斩【014】——js中的这些“this”指向都值得了解
13. 前端百题斩【015】——快速手撕call、apply、bind
14. 前端百题斩【016】——原型、构造函数和实例之间的奇妙关系
17. 一文彻底搞懂前端监控
18. 前端的葵花宝典——架构
19. canvas从入门到猪头
21. 2021 年前端宝典【超三百篇】
22. 前端也要懂机器学习(上)
23. 前端也要懂机器学习(下)
24. 学架构助力前端起飞
26. Vue源码思想在工作中的应用
27. 一文搞定Diff算法