【深入理解JS核心技术】2. 什么是原型链?

1,345 阅读50分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第30天,点击查看活动详情

原型链是用于在现有对象的基础上构建新类型的对象。它类似于基于类的语言中的继承。

对象实例的原型可以通过 Obeject.getPrototypeOf(object) 或 proto 属性获得,而构造函数的原型可通过 Object.prototype 获得。

构造函数,原型,实例的关系:

每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。

原型链的基本思想:(如果原型是另一个类型的实例?)原型当成实例。

意味着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
};

function SubType() {
 this.subproperty = false;
}

// 继承SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function() {
 return this.subproperty;
};

let instance = new SubType();
console.log(instance.getSuperValue()); // true
  1. 默认原型

默认情况下,所有引用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。

  1. 原型与继承关系

原型与实例的关系可以通过两种方式来确定。第一种方式是使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true。

确定关系的第二种方式是使用 isPrototypeOf() 方法。原型链中的每个原型都可以调用这个方法。

// 只要原型链中包含这个原型,这个方法就返回true
console.log(Object.prototype.isPrototypeOf(instance)); // true
  1. 关于方法

子类有时候需要覆盖父类的方法,或者增加父类没有的方法。这些方法必须在原型赋值之后再添加到原型上。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
}

function SubType() {
 this.subproperty = false;
}

// 继承SuperType
SubType.prototype = new SuperType();

// 新方法
SubType.prototype.getSubValue = function() {
 return this.subproperty;
};

// 覆盖已有的方法
SubType.prototype.getSuperValue = function() {
 return false;
};

let instance = new SubType();
console.log(instance.getSuperValue()); // false

重点:如果以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
};

function SubType() {
 this.subproperty = false;
};

// 继承SuperType
SubType.prototype = new SuperType();

// 通过对象字面量添加新方法,这会导致上一行无效
SubType.prototype = {
 getSubValue() {
  return this.subproperty;
 },
 someOtherMethod() {
  return false;
 }
};

let instance = new SubType();
console.log(instance.getSuperValue()); // 出错
  1. 原型链的问题

原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会在原型上的原因。

在使用原型实现继承时,原型实际上变成了另一个类型的实例。(原先的实例属性变成了原型属性)

function SuperType() {
 this.colors = ["red", "blue", "green"];
}

function SubType() { }

// 继承SuperType
SubType.prototype = new SuperType();

let instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // "red,blue,green,black"

let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black"

原型链的第二个问题:子类型在实例化时不能给父类型的构造函数传参。

未完结!更多内容尽情期待下一节~

【深入理解JS核心技术】欢迎各位观众老爷,求点赞,求关注,求转发~

低调务实优秀中国好青年 (简介) && 附加答案

中文 | English

一个 ☝️ 正经的前端学习 开源 仓库,启发来自 淘宝大佬 @冴羽 ,初心做一个真正能帮助到大家的仓库。一个人可以走的更快,但一群人才能走的更远。(非常口语化的,手写总结)

欢迎大家前来讨论,如果觉得对你的学习有一定的帮助,欢迎点个Star (此仓库每天都会准时更新)- vx联系: xiaoda0423

👤:我是哪吒: 如果你所学的东西 处于喜欢 才会有强大的动力支撑。

地址 ⬇️

github.com/webVueBlog/…

🐤 交流讨论 && 如何学习 && 转载声明 && 帮忙修正以及补充

第一:你可以直接在本仓库阅读即可,阶段性学习。 (可以转载里面的所有知识点用到任何地方,但请添加仓库的地址)有问题欢迎提交issues

🐂 阶段三十一(648)

展开查看

🐂 阶段三十(623)

展开查看

🤨 阶段二十九(598)

展开查看

🤨 阶段二十九(572)

展开查看

😛 阶段二十八(565)

展开查看

😛 阶段二十七(555)

展开查看

😛 阶段二十六(544)

展开查看

😛 阶段二十五(532)

展开查看

😛 阶段二十四(525)

展开查看

😛 阶段二十三(514)

展开查看

📕 阶段二十二(500)

展开查看

😋 阶段二十一(480)

展开查看

✔ 阶段二十(470)

展开查看

😗 阶段十九(460)

展开查看

🐉 阶段十八(450)

展开查看

🐔 阶段十七(440)

展开查看

🐟 阶段十六(425)

展开查看

🦐 阶段十五(401)

展开查看

🦂 阶段十四(384)

展开查看

😘 阶段十三(370)

展开查看

🥰 阶段十二(340)

展开查看

😉 阶段十一(324)

展开查看

🙃 阶段十(306)

展开查看

😍 阶段九(285)

展开查看

🧑🏻 阶段八(250)

展开查看

🧑🏻‍💻 阶段七(215)

展开查看

😇 阶段六(190)

展开查看

🧑🏻‍💻 阶段五(175)

展开查看

🥲 阶段四(150)

展开查看

🧑🏻‍💻 阶段三(145)

展开查看

🤣 阶段二(100)

展开查看

🧑🏻‍💻 阶段一(50)

展开查看

全栈架构师

展开查看

深入理解JS核心技术

NumberTitle
1在 JavaScript 中创建对象的可能方式有哪些
2什么是原型链
3调用、应用和绑定有什么区别
4什么是 JSON 及其常用操作
5数组切片方法的目的是什么
6数组拼接方法的目的是什么
7切片和拼接有什么区别
8你如何比较对象和地图
9== 和 === 运算符有什么区别
10什么是 lambda 或箭头函数
11什么是一级函数
12什么是一阶函数
13什么是高阶函数
14什么是一元函数
15什么是柯里化函数
16什么是纯函数
17let 关键字的作用是什么
18let 和 var 有什么区别
19选择名称let作为关键字的原因是什么
20如何在 switch 块中重新声明变量而不会出错
21什么是时间死区
22什么是 IIFE(立即调用函数表达式)
23您如何在 JavaScript 中解码或编码 URL
24什么是备忘
25什么是吊装
26ES6 中的类是什么
27什么是闭包
28什么是模块
29为什么需要模块
30javascript中的作用域是什么
31什么是服务人员
32如何使用 service worker 操作 DOM
33如何在 service worker 重启时重用信息
34什么是索引数据库
35什么是网络存储
36什么是发布消息
37什么是饼干
38为什么需要 Cookie
39cookie 中有哪些选项
40如何删除 cookie
41cookie、本地存储和会话存储有什么区别
42localStorage 和 sessionStorage 的主要区别是什么
43您如何访问网络存储
44会话存储上可用的方法有哪些
45什么是存储事件及其事件处理程序
46为什么需要网络存储
47你如何检查网络存储浏览器支持
48你如何检查网络工作者浏览器支持
49举个 web worker 的例子
50webworkers对DOM有什么限制
51什么是承诺
52为什么需要承诺
53承诺的三种状态是什么
54什么是回调函数
55为什么我们需要回调
56什么是回调地狱
57什么是服务器发送事件
58您如何接收服务器发送的事件通知
59如何检查浏览器对服务器发送事件的支持
60服务器发送的事件有哪些可用的事件
61承诺的主要规则是什么
62什么是回调中的回调
63什么是承诺链
64什么是promise.all
65承诺中比赛方法的目的是什么
66什么是javascript中的严格模式
67为什么需要严格模式
68你如何声明严格模式
69双感叹号的目的是什么
70删除运算符的目的是什么
71什么是 typeof 运算符
72什么是未定义属性
73什么是空值
74null 和 undefined 有什么区别
75什么是评估
76窗口和文档有什么区别
77你如何在javascript中访问历史记录
78你如何检测大写锁定键是否打开
79什么是 NaN
80未声明变量和未定义变量有什么区别
81什么是全局变量
82全局变量有什么问题
83什么是 NaN 属性
84isFinite 函数的目的是什么
85什么是事件流
86什么是事件冒泡
87什么是事件捕获
88如何使用 JavaScript 提交表单
89您如何找到操作系统详细信息
90文档加载和 DOMContentLoaded 事件有什么区别
91本机,主机和用户对象之间有什么区别
92用于调试 JavaScript 代码的工具或技术有哪些
93与回调相比,promise 的优缺点是什么
94属性和属性有什么区别
95什么是同源策略
96void 0的目的是什么
97JavaScript 是编译型语言还是解释型语言
98JavaScript 是区分大小写的语言吗
99Java和JavaScript之间有什么关系吗
100什么是事件
101谁创建了 JavaScript
102preventDefault 方法有什么用
103stopPropagation 方法有什么用
104return false 涉及哪些步骤
105什么是物料清单
106setTimeout 有什么用
107setInterval 有什么用
108为什么 JavaScript 被视为单线程
109什么是事件委托
110什么是 ECMAScript

👩🏻‍💻:webVueBlog的leetcode刷题📒

  1. Number题号
  2. Title题目
  3. Difficulty难度
  4. Navigation解答
NumberTitleDifficultyNavigation
1.两数之和两数之和
2.两数相加两数相加
3.无重复字符的最长子串无重复字符的最长子串

以 「早起」、「运动」、「冥想」、「写作」、「阅读」这五件能够快速改变人生的事情为切入点,帮助大家建立良好的生活习惯,技术的成长绝不是一朝一夕,良好的习惯将会帮助我们更快的进步,但在技术之外,我更希望大家能在这些事情的坚持中,收获一份自信,多一份底气,对人生多一份积极。 --- (来源:低调务实优秀中国好青年群)

License

MIT