【前端词典】继承(一) - 面试官问的你都会吗?

栏目: JavaScript · 发布时间: 5年前

内容简介:虽说标题是分两节讲有以下两个原因:继承于我们前端来说绝对是非常熟悉也必须熟悉的一个高频必懂知识点。熟悉到只要是面试一定会有关于继承的问题;而且源码中继承的使用也随处可见。

虽说标题是 继承 ,但继承这块的涉及的知识点不仅仅只是 继承 ,所以这块我会分成两个部分来讲:

  • 第一部分主讲原型以及原型链
  • 第二部分主讲继承的几种方式

分两节讲有以下两个原因:

  1. 需要了解 继承 必须对 原型和原型链 有深刻的了解,分开讲好消化
  2. 最近孩子快出生,需要更多的时间翻阅资料来保证文章的质量

前言

继承于我们前端来说绝对是非常熟悉也必须熟悉的一个高频必懂知识点。熟悉到只要是面试一定会有关于继承的问题;而且源码中继承的使用也随处可见。

可依旧有很多前端对 继承的实现和应用 没有一个整体的把握。追其原因无非有二:

  1. ECMAScript 继承 的实现方法区别于其他基于类的实现继承的面向对象(Object Oriented)语言。
  2. 工作中即使对 如何实现继承 一知半解,也一点都不耽误写逻辑代码。

无论由于哪一个原因,建议请尽快弄懂 继承的实现和应用 ,否则你可能会如同你的表情包一样——流下了没有技术的泪水。

接下来我会尽我所能讲清楚 继承 这个概念,并结合相关经典图文做辅助解释。

在讲 ECMAScript 继承的概念之前,我先说下 原型 的概念。

类与原型

讲 ECMAScript 继承的概念之前,我先说下类的概念。( 如果接触过 Java 或者是 C++ 的话,我们就知道 Java(C++)的继承都是基于类的继承 )。

类: 是面向对象(Object Oriented)语言实现信息封装的基础,称为 类类型 。每个类包含数据说明和一组操作数据或传递消息的函数。 类的实例称为对象

类: 是描述了一种代码的组织结构形式,一种在软件中对真实世界中问题领域的建模方法。

类的概念这里我就不再扩展,感兴趣的同学可以自行查阅书籍。接下来我们重点讲讲 原型 以及 原型链

原型

JavaScript 这门语言没有类的概念,所以 JavaScript 并非是基于类的继承,而是基于原型的继承。( 主要是借鉴 Self 语言原型( prototype )继承机制 )。

注意:ES6 中的 class 关键字和 OO 语言中的类的概念是不同的,下面我会讲到。ES6 的 class 其内部同样是基于原型实现的继承。

JavaScript 摒弃 转而使用 原型 作为实现继承的基础,是因为基于 原型 的继承相比基于 的继承上在概念上更为简单。首先我们明确一点, 存在的目的是为了实例化对象,而 JavaScript 可以直接通过 对象字面量语法 轻松的创建对象。

每一个函数,都有一个 prototype 属性。 所有通过函数 new 出来的对象,这个对象都有一个 __proto__ 指向这个函数的 prototype 。 当你想要使用一个对象(或者一个数组)的某个功能时:如果该对象本身具有这个功能,则直接使用;如果该对象本身没有这个功能,则去 __proto__ 中找。

1. prototype [显式原型]

prototype 是一个显式的原型属性,只有函数才拥有该属性。

每一个函数在创建之后都会拥有一个名为 prototype 的属性,这个属性指向函数的原型对象。 ( 通过 Function.prototype.bind 方法构造出来的函数是个例外,它没有 prototype 属性 )

protptype 是一个指针,指向的是一个对象。比如 Array.ptototype 指向的就是 Array 这个函数的原型对象。

【前端词典】继承(一) - 面试官问的你都会吗?

在控制台中打印 console.log(Array.prototype) 里面有很多方法。这些方法都以事先内置在 JavaScript 中,直接调用即可。上面我标红了两个特别的属性 constructor__proto__ 。这两个属性接下来我都会讲。

我们现在写一个 function noWork(){} 函数。

【前端词典】继承(一) - 面试官问的你都会吗?
当我写了一个 noWork 这个方法的时候,它自动创建了一个 prototype 指针属性(指向原型对象)。而这个被指向的原型对象自动获得了一个 constructor (构造函数)。细心的同学一定发现了: constructor 指向的是 noWork

noWork.prototype.constructor === noWork     // true
复制代码

一个函数的原型对象的构造函数是这个函数本身

如图:

【前端词典】继承(一) - 面试官问的你都会吗?

tips: 图中打印的 Array 的显式原型对象中的这些方法你都知道吗?要知道数组也是非常重要的一部分哦 ~ 咳咳咳,这是考试重点。

2. __proto__ [隐式原型]

prototype 理解起来不难, __proto__ 理解起来就会比 prototype 稍微复杂一点。不过当你理解的时候你会发现,这个过程真的很有趣。下面我们就讲讲 __proto__

其实这个属性指向了 `[[prototype]]`,但是 `[[prototype]]` 是内部属性,我们并不能访问到,所以使用 `__proto__` 来访问。

我先给个有点绕的定义:

__proto__ 指向了创建该对象的构造函数的显式原型。

我们现在还是使用 noWork 这个例子来说。我们发现 noWork 原型对象中还有另一个属性 __proto__

我们先打印这个属性:

【前端词典】继承(一) - 面试官问的你都会吗?
我们发现这个 __proto__ 指向的是 Object.prototype

我听到有人在问为什么?

  1. 因为这个 __proto__.constructor 指向的是 Object
  2. 我们知道: 一个函数的原型对象的构造函数是这个函数本身
  3. 所以这个 __proto__.constructor 指向的是 Object.prototype.constructor
  4. 进而 __proto__ 指向的是 Object.prototype

如图:

【前端词典】继承(一) - 面试官问的你都会吗?

我们来验证一下:

【前端词典】继承(一) - 面试官问的你都会吗?

至于为什么是指向 Object? 因为所有的引用类型默认都是继承 Object 。

作用

  1. 显式原型:用来实现基于原型的继承与属性的共享。
  2. 隐式原型:构成原型链,同样用于实现基于原型的继承。 举个例子,当我们使用 noWork 这个对象中的 toString() 属性时,在 noWork 中找不到,就会沿着 __proto__ 依次查找。

3. new 操作符

当我们使用 new 操作符时,生成的实例对象拥有了 __proto__ 属性。即在 new 的过程中,新对象被添加了 __proto__ 并且链接到构造函数的原型上。

new 的过程

  1. 新生成了一个对象
  2. 链接到原型
  3. 绑定 this
  4. 返回新对象

Function.__proto__ === Function.prototype

难道这代表着 Function 自己产生了自己? 要说明这个问题我们先从 Object 说起。

我们知道所有对象都可以通过原型链最终找到 Object.prototype ,虽然 Object.prototype 也是一个对象, 但是这个对象却不是 Object 创造的,而是引擎自己创建了 Object.prototype 所以可以这样说:

所有实例都是对象,但是对象不一定都是实例。

接下来我们来看 Function.prototype 这个特殊的对象:

打印这个对象,会发现这个对象其实是一个函数。我们知道函数都是通过 new Function() 生成的,难道 Function.prototype 也是通过 new Function() 产生的吗?这个函数也是引擎自己创建的。

首先引擎创建了 Object.prototype ,然后创建了 Function.prototype ,并且通过 __proto__ 将两者联系了起来。

这就是为什么 Function.prototype.bind() 没有 prototype 属性。因为 Function.prototype 是引擎创建出来的对象,引擎认为不需要给这个对象添加 prototype 属性。

对于为什么 Function.__proto__ 会等于 Function.prototype ? 我看到的一个解释是这样的:

其他所有的构造函数都可以通过原型链找到 Function.prototype ,并且 function Function() 本质也是一个函数,为了不产生混乱就将 function Function()__proto__ 联系到了 Function.prototype 上。

继承的几种方式

未完待续

参考

  1. 《JavaScript 高级程序设计》
  2. 《你不知道的 JavaScript - 上》
  3. 《JavaScript 语言精粹》
  4. ~zepto设计和源码分析

前端词典系列

《前端词典》这个系列会持续更新,每一期我都会讲一个出现频率较高的知识点。希望大家在阅读的过程当中可以斧正文中出现不严谨或是错误的地方,本人将不胜感激;若通过本系列而有所得,本人亦将不胜欣喜。

内容:前端以及网络相关知识点的介绍并加以实际应用作为辅助。

目的:这个系列的文章可以对读者起到一点帮助,解开一些迷惑。

希望各位多指点一二,不吝赐教。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

玩法变了

玩法变了

胖胡斐 / 电子工业出版社 / 2012-1 / 39.00元

《玩法变了:淘宝卖家运赢弱品牌时代》内容简介:目前网店的销售、运营、营销都碰到很多瓶颈,钱不再好赚,流量不再免费的情况下。网店常常陷入不断找流量的怪圈中,而真正潜心提升基本功的网店却拥有更多机会,网店需要突围。《玩法变了:淘宝卖家运赢弱品牌时代》系统地介绍整个电子商务零售领域的玩法变化,从网店基本功到网店品牌建设都有涉及。《玩法变了:淘宝卖家运赢弱品牌时代》将是网店用户重要的方法论和实践指南。一起来看看 《玩法变了》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码