前端百题斩【017】——一基础、二主线、双机制理解原型链

执鸢者
English
写该系列文章的初衷是“让每位前端工程师掌握高频知识点,为工作助力”。这是前端百题斩的第17斩,希望朋友们关注公众号“执鸢者”,用知识武装自己的头脑。

img

17.1 基础

在js中,每一个对象都包含一个原型属性,用于关联另一个对象,关联后就能够使用那个对象的属性和方法;对象之间通过原型关联到一起,就好比用一条锁链将一个个对象连接在一起,在与各个对象挂钩后,最终形成了一条原型链。(注意:js中的对象分为函数对象和普通对象,这两类对象均具备__ proto __属性,但是只有函数对象才有prototype属性。)

17.2 原型链流程

下图是网上流传的学习原型链的一幅神图,我们先贴出来一点一点分析。

img

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__);
上述的打印结果如下所示,其打印结果与上述普通对象的链路完全一致。

image-20210530172247273.png

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__);
上述的打印结果如下所示,其打印结果与上述函数对象的链路完全一致。

image-20210606131621751.png

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.关注公众号执鸢者,与号主一起斩杀前端百题

阅读 360

摸摸头,编程使我快乐。

1.5k 声望
2.5k 粉丝
0 条评论
你知道吗?

摸摸头,编程使我快乐。

1.5k 声望
2.5k 粉丝
文章目录
宣传栏