8000 字读完《JavaScript 语言精粹(修订版)》
↑↑↑↑↑↑ 脑图镇楼 ↑↑↑↑↑↑
Hello,各位小伙伴大家好。
今天我们来为大家讲一本书,就是这个《JavaScript 语言精粹修订版》,作者是:道格拉斯·克罗克福德
我手里的这本是《2017年10月第16次印刷版本》,距离现在已经有 5 年多了。但是这本书依然被奉为《讲解 JavaScript 的一本神书》,特别适合 初级、中级 前端工程师进行阅读。
但是大家要注意,虽然说这本书是 2017年
印刷的,但是书中提到的概念、定义并没有 考虑 ES6
相关的东西,也就是说它是 纯粹的、ES6 之前的 JavaScript 精华的讲解
整本书中所有的内容,我把它分为 4 大块:
- 前言部分
- 核心部分
- 其他部分
- 附录部分
在讲解完这四部分之后,我们会分析一下这本书在当下时间段针对国内开发者的优缺点,也就是最后的总结。
好,那么废话不多说,下面我们来看一下本书中的内容:
前言
在前言部分,作者提到了一个非常有意思的事情,那就是《为什么一定要使用 JavaScript》,他说:因为你没得选。
针对于 web浏览器而言,JavaScript 是唯一的编程语言,同时它也是世界上最被轻视的语言之一。
我们知道, JavaScript 是 布蘭登·艾克 花了 10 天的时间开发并且设计完成的,所以它内部必然包含了很多的优秀想法与糟糕的想法。
那么都有什么优秀的方法呢? 作者认为:
- 函数
- 弱类型
- 动态对象
- 对象字面量
- ...
这些东西,都可以被认为是优秀的想法,也就是 精华
但是同时,内部也有很多糟糕的想法,也就是 糟粕,比如:基于全局变量的编程模型。
所以:JavaScript 是一个反差鲜明的语言,它的糟粕和精华一样显眼
而本书,将主要讲解: JavaScript 的精华部分,至于 糟粕,将会在附录部分进行说明。
核心
那么下面我们就进入到本书的核心精华部分,整个精华部分被分为 6 块,分别是:
- 语法
- 对象
- 函数
- 继承
- 数组
- 方法
那么首先,咱们先来看语法部分。
语法:
整个语法部分涉及到的是整个 JavaScript
的基础语法。
注释
首先针对于注释而言,作者提出 JavaScript
中的注释主要分为两种:
- 单行注释
- 多行注释
单行注释是 两个 / ,这个在日常开发中是比较常见的。
而针对于多行注释来说,作者主要提供了一种,就是: **双斜杠中间,放入两个 *** ,这种多行注释的形式,作者并 不推荐 使用。
/*
多行注释内容
*/
但是大家要注意,在咱们现在的日常开发中,多行注释,除了作者提到了这一种之外,其实还有另外一种,那就是:
/**
* 多行注释内容
/
这种注释形式用在 函数上 还是非常指的推荐的。
标识符
接下来是标识符,所谓标识符指的就是:JavaScript
中的保留字。
书中列举出来了一分部,但是除此之外,还有一些其他的保留字大家需要注意。
这些保留字 不可以 被当做 变量名 使用。
数字
针对于很多编程语言来说,都提供了多种的数字类型。比如: java
就提供了 int、long、double、float 等
多种数字类型。
但是针对于 JavaScript
来说,它只有一种数字类型,就是 number
,除此之外再无其他。
字符串
而对于 JavaScript
中的字符串类型而言,书中主要从两个方面进行了描述:
-
首先是字面量:所谓字面量指的就是 快速创建某种类型的方式。对于字符串来说,它有两种字面量形式: 单引号和双引号。在日常开发中,我们更推荐使用 单引号 的字面量形式。
-
第二个叫做特性:这里的特性主要有三个:
- 首先第一个叫做 可拼接:多个字符串是可以通过 + 的形式进行拼接的。
- 第二个叫做
可 length
:咱们可以通过字符串.length
的形式,获取字符串的长度 - 第三个叫做 有方法:
JavaScript
中的字符串提供了非常多的方法,这个咱们把它放到 方法 这一大块中再去说就可以。
语句
JavaScript
被称作是一个图灵完备的编程语言。所以它必然要具备 变量声明、逻辑判断 等语句。
JavaScript
中的语句可以写在 <script>
标签 中,每一对花括号中间就可以被叫做一组语句。
书中把 JavaScript
的语句分为 4 大块:
-
首先是声明语句:
JavaScript
想要声明变量主要有三种形式- 第一种是
var
:它是在ES6
之前唯一的声明变量的方式,现在已经不推荐使用了。 - 第二种是
let
:在ES6
之后可以通过它来定义变量 - 最后是
const
:在ES6
之后可以通过它来定义常量
- 第一种是
-
其次是条件语句:
JavaScript
中的条件语句主要有两个- 第一个是
if
- 第二个是
switch
这两种条件判断形式,在很多的编程语言中都是存在的。但是
JavaScript
中判断条件有些不太一样的地方。在
JavaScript
中 任何表达式 都可以被作为判断条件,并且 有且仅有 6 个值 在条件判断中会被作为 假,它们分别是:false、null、undefined、空字符串、数字 0 、NaN
。除此之外,其他的所有值都会被判断为 真 - 第一个是
-
再往后就是循环语句:
JavaScript
中循环语句主要有三种- 第一个是
for
循环 - 第二个是
while
循环 - 第三种是
do...while
循环
同时,针对于
for
循环来说,又可以被分为: 普通 for 循环 和 forIn 循环 - 第一个是
-
最后就是强制跳转语句,所谓强制跳转语句指的是: 会强制更改程序执行顺序的语句,这些语句在日常开发中也是被经常使用的:
- 比如
break
:它会让程序 退出循环 || 退出 switch 语句 - 而
continue
:会让程序 终止当前循环 - 然后是
renturn
:它会终止函数的执行 throw
:会通过 抛出异常的形式,终止程序执行try...catch
:会通过 捕获异常 的形式,让程序强制跳转到其他的逻辑中
- 比如
表达式
说完语句之后,下面就是表达式。
作者对表达式进行了明确的定义,指的是: 一组代码的集合,并且返回一个值
JavaScript
中的表达式 5 个,分别为:
- 算数表达式
- 字符串表达式
- 逻辑值表达式
- 左值表达式
- 基本表达式
字面量(对象)
在前面咱们说到了 JavaScript
中存在字面量的概念。我们可以通过字面量的形式直接定义 字符串
同时,字面量也有很多其他的使用场景,比如:可以使用字面量定义对象或数组,而不需要像其他的语言一样,必须先 new
一下。
函数
整个语法部分,最后一块就是函数,但是在书中针对 语法部分函数 的讲解比较粗糙,所以这一块咱们放到后面单独的函数模块进行说明。
对象
语法部分说完之后,接下来咱们来看下书中 对象 的部分。
对象在 JavaScript
中是一个非常特殊的概念。
定义
在 JavaScript
中数据类型主要被分为两种:
- 简单数据类型:有
number、string、boolean、null、undefined、symbol、bigint
- 除了简单数据类型之外,其他的都被叫做 复杂数据类型,有:
数组、函数、正则表达式、对象
。 而JavaScript
中,所有的复杂数据类型,都被统称为 对象。
字面量
对象有字面量的创建形式,这个在刚才已经有介绍了,所以这里就不在多复述了。
检索与更新
同时对于对象来说,它可以 获取值(检索) ,也可以 修改值(更新) 。
JavaScript
中提供了两种检索与更新的形式:
- 第一种是通过
. 语法
:这种方式最为简单易懂,是大多数情况下推荐使用的方式 - 第二种是通过
[] 语法
:[]
内部可以放一个变量,适用于 根据变量取值的情况
原型
同时 JavaScript
中提供了原型的概念,基于原型还延伸出了原型继承的概念。
而对于对象的原型,咱们放到 继承 这里,再进行详细说明。
反射
然后咱们来看 反射。可以很多小伙伴看到反射这个词的时候,会比较懵。
其实在 JavaScript
里面,没有反射的明确定义。大家就把它作为是 作者的一个称呼即可
反射这一块里面,主要包含了两部分:
- 利用
typeof
获取变量的类型 - 利用
hasOwnProperty
判断 对象自身属性中是否具有指定的属性,具有则返回true
,否则则是false
枚举
hasOwnProperty
这个方法在 “枚举” 的时候会非常有用。
和反射一样,JavaScript
中同样没有枚举的明确概念。它一样是作者的一个称呼。
书中的枚举指的主要是: 遍历一个对象并且获取该对象自身的所有属性。
遍历可以直接通过 forIn
循环执行,而判断是否为对象自身属性,则需要借助 hasOwnProperty
方法
删除
最后,针对于对象模块,作者还提到了 删除 的概念。
我们可以利用 delete
关键字,直接删除对象中的指定属性。这也是很方便的。
函数
在对象说完之后,下面咱们就进入到了一个 大块 了,那就是函数!
在 函数 这一章里面,存在很多的 落后性 和 描述的偏差,同时也有很多的 精华。
具体是什么,咱们往下看就知道了。
精华
在函数这一章的开篇,作者有一句话我非常喜欢,它描述了整个编程的本质,咱们一起来读一下:所谓编程,就是将一组需求分解成一组函数与数据结构的技能
在这句话中,把函数的作用推到了一个非常重要的位置。
事实也同样如此。
所以书中花费了非常大的章节来介绍函数,大家看脑图也可以看的出来。
那么下面,咱们就进入到函数的内容之中。
函数对象
咱们之前说过,在 JavaScript
中除了基本数据类型之外,其他的都是对象。
所以函数本质上也是一个对象。只不过它拥有一个叫做 “调用” 的属性,可以被调用而已。
函数字面量
而如果想要定义函数,那么可以通过 函数字面量 的形式来进行定义。
所谓的函数字面量,其实就是咱们平时定义函数的方式,一共分为两种:
- 命名函数:
function f (a, b) { ... }
- 匿名函数:
const f = function (a, b) { ... }
调用
而在函数调用时,书中一共分为两部分去说:
-
首先第一部分是 函数可以调用其他函数:这个只要大家使用过编程语言,那么应该都很好理解。这种方式会 暂停当前函数执行,传递控制权和参数给新的函数
-
第二种是 附加参数:在
JavaScript
的函数中,存在两个附加参数:-
第一个是
this
:它的值取决于调用的模式。书中把调用模式分成了 4 大类:- 前三大类 方法调用、函数调用、构造器调用 中
this
指向调用方 - 最后一大类 apply 调用 中,
this
指向 指定值
- 前三大类 方法调用、函数调用、构造器调用 中
-
第二个
arguments
:它表示函数得到的所有实际参数
-
构造器模式
函数除了可以被直接 调用 之外,还可以被当做 构造器使用,也就是所谓的 构造器模式。
关于 构造器模式,书中主要明确了四个方面,分别是:
JavaScript
是一门基于原型继承的语言,这就意味着 对象可以直接从其他对象中继承属性。 关于继承的话题,咱们在后面单独说- 第二个是: 构造器本身就是函数。
- 第三就是: 构造器不通过小括号的形式直接调用,而是要 配合 new 关键字 使用
- 最后就是:根据 约定,构造器它的 首字母要大写
这四块是非常重要的,哪怕是在当下时间段依然是行之有效的。
apply 调用模式
在前面,咱们提到了 apply 调用模式,咱们知道所谓的 apply 调用模式
实际上是分为三个方法的,分别是:
apply
call
bind
这三个方法的核心作用,就是 改变 this 指向
参数
在 参数 这个小节里面,同样书中主要提到的就是 arguments
,这个咱们在前面也说过了,它主要是获取 所有实际参数 的。
返回值
再往后,书中对 函数的返回值 进行了一些说明。
大家需要知道的,主要是有三点:
- 首先第一点: 函数必然存在返回值。如果你什么都不返回,那么函数默认返回
undefined
- 然后: 可以通过
renturn
让函数提前返回指定的值,并且中止执行 - 第三:函数也可以配合
new
使用,这样会返回this
看到这大家有没有发现,书中讲过的很多东西,咱们在日常开发中大部分都是知道的。
但是书中把开发的一些 “经验” ,变成了一套具体的 1、2、3 。
我在看的过程中,有时候确实会有一种: “哦~ 原来如此” 或者是 “嗯,确实是这样” 的一种感觉
异常
那么下面咱们继续来往下看
书中专门在函数中,对异常进行了一个说明。
但是说明的重点依然是 throw
语句,抛出异常。在抛出异常的,它可以终止函数的执行。
扩充类型的功能
作者把基于原型继承称为: 扩充类型的功能
但是本质上还是 原型继承,这个咱们依然还是在 继承 模块中去说就可以。
递归
递归是函数调用非常常见并且复杂的场景。
书中也对 递归 进行了详细说明,说明的方式是通过两部分:
- 第一个就是什么叫递归,所谓递归指的就是: 直接或间接调用自身的函数
- 接下来是递归的场景: 递归把一个复杂问题分解为一组相似的子问题,每一个都用一个寻常解去解决,这是典型的美式语言。同时作者还通过一个 汉诺塔游戏 的案例,进行了举例说明
作用域
接下来作者提到了作用域的概念。
但是这一块,明显具备非常大的局限性,因为作者的很多观念完全是基于 ES6
之前的逻辑去说的。
比如,作者提到: JavaScript
中不存在块级作用域。
这个在当前场景下明显是不对的。
所以我看的这本书,虽然是 2017 年
印刷的,但是内容感觉更加偏老一些。
闭包
接下来是闭包的逻辑。
这里作者对闭包进行了定义: 内部函数可以访问定义他们的外部函数的参数和变量 ,这样的函数就是闭包。
我针对于这句话加上我个人的理解,也总结了一句: 可以访问其它函数作用域中变量的函数 ,就是闭包。
大家可以看看哪个好理解,就理解哪一句就可以。
这里我列举了一段代码:
function a () {
const name = '张三'
return function b () {
return name
}
}
console.log(a()()) // 张三
在这段代码中, b
函数 就是闭包函数
回调
在往下是 回调 的概念。
这里其实主要就是说明了一点: 函数可以作为参数进行回调使用
模块
结合 闭包 和 回调 ,作者提到了 模块 这样的概念。
当 使用函数和闭包 时,可以构造一个模块。
那么什么是模块呢? 作者同样给出了定义: 模块是一个提供接口却隐藏状态与实现的函数或对象
只看概念,非常难以理解,咱们通过这个代码来去看:
let name = '张三' // 此时 name 为全局变量,可以被任意修改
function a () {
// 此时 name 为函数作用域变量
// 通过 const b = a() 得到 b 函数,然后进行调用
// name 不可以被外界修改
let name = '张三'
return function b () {
return name
}
}
通过这种模块的方式,来缓解 基于全局变量的编程模式 所带来的问题。
级联
所谓 级联,是作者的称呼。
咱们更喜欢把它叫做 链式调用,明确了概念大家应该就知道是什么了。
柯里化
作者专门讲解了 柯里化,他对柯里化是这样定义的,他说: 把函数与传递给它的参数相结合,产生一个新的函数。 这叫做柯里化。
这个定义和咱们的平常认知不同,在咱们的认知中,柯里化指的应该是: 柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)
因为这本书原本是英文的,咱们拿到的都是 转译之后的译本,所以关于一些定义,大家客观看待就可以了。
记忆
整个函数最后一块,提到了一个 记忆 的词汇。
这个在咱们日常开发中不会这里称呼,这里的记忆指的其实就是: 把函数的操作结果,保存到一个对象中,从而避免重复运算。
书中也拒了一些例子,但是本质上应该是一个类似算法的概念。
总结
那么到这里,关于函数这一章咱们就说完了。
从函数这一章中,其实咱们就可以明确的感受出来: 书中的内容具备一定的落后性(比如:块级作用域) 和 译文导致的一些描述的偏差(比如:柯里化) ,但是 其中也有很多的精华(比如:返回值、递归、闭包)
所以这本书,咱们再去看的时候,一定要客观分析一下才可以。
继承
那么下面咱们来看 继承 这个章节
这个章节的内容不算特别多,至少相比于 函数 是这样的。
书中并没有详细的讲解 JavaScript
中所有继承的方式,以及代码。
更多的还是从理念的层次来去说的。同时 依然包含很多落后性
精华
首先本章一开始先明确了 JavaScript
的继承方式: JavaScript 是弱类型的语言,提供了多种继承的模式,而非传统的类继承
伪类
然后作者提到了 伪类 这样的一个词汇
这个伪类,说白了就是 构造函数,也就是: 首字母大写的普通函数
对象说明符
这里作者又提到了一个新的词汇:对象说明符。
并且列举出来了一个场景: 当一个函数接收多个参数时,记住参数的顺序非常困难
比如:
maker(f, l, m, c, s)
所以,与其这么写,倒不如这样写:
maker({
first: f,
middle: m,
last: l,
state, s,
city: c
})
简单来说,也就是: 把多个参数,合并成一个用对象表示的参数。
作者把这样的一种方式叫做: 对象说明符。
原型
原型是继承中非常重要的概念。
但是因为书中的字数限制,作者并没有对原型展开了详细说,而只是明确了两点:
-
首先第一点是基于原型继承的概念: 一个新对象可以继承一个旧对象的属性
-
第二个是差异化继承:继承本质上需要具备差异,通过一个小的
demo
进行了明确const person = { name: '张三', age: 18 } const newPerson = Object.create(person) newPerson.name = '李四'
这样,就完成了一个简单的差异化继承。
函数化
在讲完了原型之后,作者提到了一个 函数化 的概念。
作者提出: 原型的继承模式会导致没有私有变量。
如果大家使用过 ts
或者其他的 强类型编程语言(比如:java) 那么可以就知道所谓私有变量是什么意思了。
同时作者也通过一段代码来描述了 如何在原型继承的模式下具备私有变量。
这段代码比较复杂,也有点难以理解。但是在当下的场景中,因为 ES6
之后提出了 class
的概念,所以现在咱们其实是有了更简单的方式定义私有变量的。
所以这段代码的意义就不大了。
部件
整个继承最后一块就是 部件
所谓部件指的就是: 对象(这里是函数)的属性或方法。
每一个属性或方法都可以被称作是一个部件。
总结
整个继承的章节,内容并不多。
书中也没有大书特书的写关于原型继承的代码。
所以整个继承章节看下来,不会很累,概念性的东西居多。
数组
继承讲解完成之后,新的一个章节叫做 数组
定义
这里作者对于数组的定义比较有意思,他拿传统数组和 JavaScript 数组
进行了对比:
-
针对于传统数组来说:数组是一段线性分配的内存,它通过整数计算偏移并访问其中的元素
-
但是
JavaScript
中的数组不同:- 首先: JavaScript 中并不存在数组一样的数据结构
JavaScript
只不过是提供了 类数组特性的对象
咱们之前说过 js 中除了基本数据类型,其他的都是对象,这里就能够呼应上了。
数组字面量
这个比较简单,就是通过 []
定义数组
长度
想要获取数组长度,通过 .length
属性获取
删除
想要删除数组的元素,书中提到了两种方式:
- 因为数组本质上是对象,所以依然可以使用
delete
关键字删除。但是这种删除方式,会导致原来的位置留下 “空洞” - 而第二种方式,是咱们比较常用的,那就是通过
splice
进行删除
枚举
所谓的枚举,其实指的就是咱们常说的 遍历
而数组的遍历常用的方式主要是两种:
forIn
循环,但是这样无法保证顺序- 第二种是 普通的 for 循环,这也是咱们常用的方式
其实除了这两种方式之外,大家应该还能想到别的,比如: forEach
方法。
容易混淆的地方
书中专门花了一个小节来去定义 数组与对象 容易混淆的地方。
其中核心就是当使用 typeof
的时候,typeof
无法区分出 对象和数组。
所以作者给出了一个方式来进行区分:
function is_array (value) {
return Object.prototype.toString.apply(value) === '[object Array]'
}
这种方式放到现在依然可用。
除此之外,其实还有另外一种比较常用的方式,作者没有提到,那就是 instanceof
。
方法
数组中提供了一些被继承的方法,这些方法,咱们放到 方法 这一章去说就可以了。
指定初始值
书中关于数组的最后一个小节讲解了 数组初始值 相关的一些东西,主要是有两点:
- 第一点就是: 数组没有预设值。通过
[]
定义数组后,会是一个空数组(本来难道不应该是这样吗?) - 第二点就是:
JavaScript
中本质上没有多维数组的概念,所谓的多维数组不过是 以数组为元素 产生的
总结
整个数组的环节,内容还是比较简单的。
相当于把 JavaScript
中数组的一些核心特性进行了讲解。
方法
再往后就是书中核心部分的最后一块了,也就是 方法
书中对于方法的讲解主要是通过两部分:
-
第一部分是对方法进行了定义,所谓方法指的是:当一个函数被保存为对象的一个属性时,那么这个函数就被叫做是方法。
-
第二部分类似于一个
API
文档。详细的介绍了:这四大类的一些原型继承方法。
这些方法,在 MDN
文档中都可以直接查看,咱们这里就不去详细说了。
核心部分总结
核心部分讲解完成之后,其实书中绝大部分 精华 咱们就已经全部梳理完成了。
其他
除了大部分的精华之外,书中还提到了一些 其他 的东西,比如:
- 正则表达式
- 代码风格
- 优美的特性
咱们一个一个去说。
正则表达式
首先针对于正则表达式来说。
因为本书并不是一个专门讲解正则表达式的书籍,所以书中关于正则的内容并不多。很多地方也并不详细。
所以我并不是很推荐大家去看本书中关于正则的部分。
如果大家想要了解正则,倒不如到 MDN 文档 中进行查看。
代码风格和优美的特性
针对于 代码风格和优美的特性 这两块,因为 作者对 JavaScript 语法规范的理解,但并不完全适合于国内环境,所以这两部分对于咱们的参考意义也不是很大。
但是这里有一句话写的很好,我摘抄了下来,咱们可以一起看一下
我们喜欢简单,追求简洁易用,但是当产品缺乏这种特性时,就需要自己去创造它。
附录
最后就是整本书的 附录 部分。
这部分主要是分成了 5 块。
其中前两块:
- 毒瘤
- 糟粕
比较有意思,咱们可以一起来看一下。
至于后三块:
JSLint
语法图
JSON
不在咱们本次的探讨范围之内。
毒瘤
作者把 JavaScript
中非常差劲的特性叫做 毒瘤。意思是: 不除不快
这里面涉及到的语法非常的多,咱们简单过一下即可:
- 全局变量:中大型项目中,全局变量可以被任意修改,会使得程序的行为变得极度复杂
- 作用域:无块级作用域
- 自动插入分号:不合时宜的自动插入
- 保留字:大量的保留字不可以被用作变量名
unicode
:unicode
把一对字符视为一个单一的字符,而JavaScript认为一对字符是两个不同的字符typeof
:typeof
的返回总是很 “奇怪”parseInt
:遇到非数字时会停止解析,而不是抛出一个错误+
:既可以让数字相加,也可以链接字符串- 浮点数:二进制的浮点数不能正确的处理十进制的小数
NaN
:NaN
表示不是一个数字,同时它的一些运算也会让人感到奇怪- 伪数组:
JavaScript
中没有真正的数组,却又存在伪数组的概念 - 假值:
0、NaN、''、false、null、undefined
在逻辑判断中都会被认为假 hasOwnProperty
:hasOwnProperty
是一个方法而不是运算符,所以在任何对象中,他可以被替换掉- 对象:
JavaScript
中的对象永远不会是真的空对象,因为它们可以从原型链中取得成员属性
糟粕
作者把一些不符合规范,但是可以使用的代码,叫做 糟粕
主要有:
==
:不判断类型,所以尽量不要使用它with
:改变一段语句的作用域链eval
:传递字符串给 JavaScript 编译器,会使得代码更加难以阅读continue
:作者发现移除 continue 之后,性能会得到改善switch
穿越:必须明确中断 case,否则会穿越到下一个- 缺少块的语句
++ --
:这两个运算符鼓励了一种不够谨慎的编程风格- 位运算符:
JavaScript
执行环境一般不接触硬件,所以执行非常慢 function
语句对比function
表达式:多种定义方式让人困惑- 类型的包装对象:你应该从来没有使用过 new Boolean(false)。所以作者认为:这是完全没有必要,并且令人困惑的语法
总结
OK
,那么到这里整本书中所有的内容,咱们就已经全部讲解完了。
针对于《JavaScript 语言精粹修订版》来说,它的优点是非常明确的:
- 体量小
- 初、中级工程师可以通过它快速理清 JavaScript 语言精粹
但是它的缺点也是非常突出:
- 内容偏老,针对 ES6 之前的语法
- 内容多为直译,导致有时候一定定义和词汇可能会让人很困惑
- 书中包含大量的作者主观表述,可能并不一定那么精准,大家需要客观看待。(比如: vue 中就大量的使用到了“糟粕” )
转载自:https://juejin.cn/post/7193625406636261413