第2章词法结构
所谓词法结构指的是: 如何使用这门语言编写程序 的方式。
JavaScript
的词法结构主要包含了 5 个部分:
- 注释
- 字面量
- 标识符和保留字
Unicode
- 分号
注释
JavaScript
的注释分为两大类,一共有三种写法:
上图的第一种为 单行注释,剩下的两种为 多行注释。
这里有一个小点大家注意,第三种注释方式配合 VS Code
可以让我们在使用 js
函数获得对应的注释提示:
可选的分号
我们知道在 JS
中分号并不是一个强制必须要有的东西,并且根据现在企业开发的标准,很多时候是 不允许 写结尾分号的。
这种不允许在某些情况下,可能会导致一些错误。比如:
这样的代码,一旦我们通过格式化处理,那么就会被合并被一行:
所以,此时我们就增加一些 “防御性” 的分号,避免这种情况出现:
另外有一个小的细节点需要注意,那就是 一定不能在return、break或continue等关键字后加入《换行符》,这里作者给我们列举了实例:
第3章 类型、值和变量
在 JS
中类型一般被分为两大类:
- 简单数据类型:作者称其为 原始类型
- 复杂数据类型:作者称其为 特殊类型
整个第三章中,所讲解的主要就是这两大类型的内容。
原始类型
首先咱们先来看原始类型,整个原始类型包含了 7 种类型的值: number、string、boolean、null、undefined、symbol、bigint
。
这 7 种数据类型我们不会一个一个都去讲,我们主要来看其中 5 个。
- 首先是
number
:在JS
中,无论是整数还是小数都被称为number
类型。但是大家要注意的是:JS
中无法精确表示浮点数。比如:0.3 - 0.2
是不等于0.1
的。所以说JS
无法进行精确地浮点数表示。 - 接下来是
null
和undefined
:这两个值在JS
中都被称为是 假性值。但是它们也有不太一样的地方。null
是一个特殊值,通常被用来表示 某个值不存在,它是一个object
类型,我们可以使用typeof null === 'object'
来进行测试。 - 而
undefined
它表示一个 “更深层次的不存在”,当我们定义一个变量但不进行赋值时,那么这个变量默认是undefined
。undefined
是一个单独的类型,我们可以使用typeof undefined === 'undefined'
来进行测试。 - 最后是
symbol
和bigint
:这两个都是ES6
之后新增的数据类型。其中symbol
表示 唯一的值。我们可以通过symbol
得到一个永远都不会重复的结果Symbol('a') === Symbol('a') // false
。 - 而
bigint
表示的是 大数字。默认情况下JS
中的number
类型只能表示-2^53 -- 2^53
之间,超过这个范围就无法精准表示了。所以ES
推出了bigint
来表示大数字。使用bigint
非常简单,只需要在 **大数字后面加上 n ** 就可以了,同时需要注意bigint
只能是 整数,另外bigint
不能与number
进行算术运算。
特殊类型
接下来我们来看特殊类型。 JS
中的特殊类型只有一个,那就是 object
。或者说:在 JS
所有不属于原始类型的都是特殊类型。
比如:Array
、Object
、Function
、Set
等等
这些特殊类型我们会在 第六章 - 第九章
再去进行详细讲解。
第4章 表达式与操作符
表达式
在 JS 中你的每一行语句,都可以被称为是一个表达式。
操作符
条件式调用
首先是 条件式调用:在我们的日常开发中,如果一个对象为 假性值,那么当我们获取这个对象的属性时,会得到一个错误:
为了解决这样的问题,在 ES2020
中提供了一个新的语法 条件式调用,可以让我们避免这种错误:
在 obj
后面加上一个 ?
,如果 obj
为假性值,则会得到一个 undefined
。而不会抛出异常。
in 操作符
in
操作符用来判断 左侧值是否是右侧对象的属性名,返回一个 boolean
类型的值。
instanceof 操作符
instanceof
操作符用来判断 左侧值是否是右侧类的实例,返回一个 boolean
类型的值。
typeof 操作符
typeof 操作符
我们在前面使用过,它可以用来 判断一个值的类型。它可以判断的所有类型如下表所示:
delete 操作符
delete
操作符可以用来 删除一个对象或数组的指定属性或元素:
eval() 函数(操作符)
eval()
是一个函数,但是在这里作者把它作为操作符来进行讲解。
eval()
可以接收一个 字符串,这个字符串应该是一段表达式。然后 JS引擎
会把这段字符串当做 JavaScript
代码来进行执行。
?? 先定义操作符
?? 先定义操作符
有点类似于 || 操作符
。但是不同的地方在于 || 操作符
中 数字 0
会被作为假性值判断为假,但是在 ?? 先定义操作符
中 数字 0
会被作为真来进行处理。
第5章 语句
循环语句
循环语句指的是 包含循环的语句。在
JS
中可以产生循环功能的语法非常多,比如:while、do/while、for
这三个都是基本的循环语法,这里咱们不去详细说。除此之外,还有一些
ES6
之后新增的循环方式:首先是
for/of
循环:for/of
循环,不可以循环对象,只能循环非对象,比如Array、Map
都可以利用for/of
进行循环操作。当数组使用for/of
进行循环时,每个循环对象表示数组的item
。当Map
进行循环时,每个循环对象是一个 数组,我们可以通过[] 解构
的方式,拿到对应item
的key 和 value
。其次是
for/in
循环:for/in
循环比较简单,它既可以循环对象,也可以循环数组。最后是
for/await与异步迭代
循环:这一块涉及到了迭代器和异步的部分,咱们把它放到第12章 迭代器与生成器 和 第13章 异步JavaScript
中在进行讲解。
跳转语句
所谓跳转语句指的是:会修改代码执行顺序的语句。
JS
中的跳转语句一共分为7
类:break、continue、return、yield、throw、try/catch/finally
,咱们一个一个来说。首先是
break
:它通常配合循环或者switch
进行使用,表示退出当前循环或switch
条件判断。
continue
:通常配合循环使用,它表示 跳出当前循环,继续进行下一次循环。
return
:return
语句只能出现在函数体内,表示返回值,并终止函数执行。
yield
: 主要配合生成器函数来进行使用,这个咱们等到第12章 迭代器与生成器
时再进行说明。
throw
:表示抛出一个异常,通常情况下,这会终止程序的执行。
try/catch/finally
:可以捕获异常。当try
中的代码块出现异常时,代码会进入catch
执行,最终无论结果如何都会执行finally
。
第6章 对象
在 JS
中,对象是一个属性的 无序集合,所有用 {}
包裹,并且包含 key:value
结构的值都是一个对象。
想要创建一个对象的话,一共有三种方式:
- 对象字面量:这是最常用的一种方式
const obj = { name: '张三' }
- new 创建:利用
Object
构造函数,配合new
关键字,创建对象实例const obj = new Object
- 原型创建:通过
Object.create
方法创建对象实例
而想要创建对象属性的话,那么一共有两种方式:
- . 操作符:
obj.key
[key]
:obj[key]
想要删除对象中的某个属性,可以利用咱们前面提到的 delete
关键字。
在 JS
中,如果想要测试某个属性是否属于指定对象,那么一共有三种方式:
- in 操作符:咱们之前有提到过这个操作符,这里就不再多说了。
hasOwnProperty
方法:当前方法可以 测试指定属性是否为对象的自有属性。propertyIsEnumerable 方法
:当前方法可以 测试指定属性是否为对象的可枚举属性。
而如果想要 依赖现有对象,扩展出其他对象的话,那么有两种方式:
Object.assign()
:该方法可以将所有可枚举(Object.propertyIsEnumerable()
返回 true)的自有(Object.hasOwnProperty()
返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。扩展操作符...
:利用ES6
提供的扩展操作符
,可以把多个对象合并成一个新的对象。
除此之外,JS
还提供了序列化的方法,所谓的序列化指的是 把对象的状态转换为字符串的过程,之后可以从中恢复对象的状态 。在 JS 中,可以通过 JSON.parse
和 JSON.stringify
来完成对象的序列化过程。
最后就是 对象字面量扩展语法,这些扩展方法有些可能比较冷僻,但是有的确实在日常开发中存在一些价值,所以我们这里需要拿出来一些时间来说一下。
-
首先是 简写属性:这种语法是开发中非常常见的语法,当
key 和 value
为相同的名称时,可以简写。 -
其次是 计算的属性名:有些时候我们可能期望使用变量来作为对象的
key
,此时就需要用到这种计算的属性名。 -
然后是 简写方法:这个也是非常常见的一种写法。常见到很多同学都不认为这是一种简写的写法。
-
最后是 属性的获取方法与设置方法:我们可以通过
set
和get
表示来标记一个对象的方法,这样这个方法就可以像调用属性一样进行调用了。vue3
中的ref
就是通过这种方式实现的响应性。
第7章 数组
JS
提供了两个 工厂方法 来创建数组:
-
第一个是
Array.of()
:可以通过 可变数量的参数 创建一个新的Array
实例,而不需要考虑参数的数量或类型。 -
第二个是
Array.from()
:这个方法的主要价值是可以把 把类数组转化为真实数组。关于类数组我们会在下面讲解到
想要添加或者删除数组元素的话,这里咱们各列举三种方式:
- 添加
Array.prototype.push()
:把指定元素添加对数组的最后Array.prototype.unshift()
:把指定元素添加到数组的最前arr[1] = 'xx'
:把指定元素添加到数组的指定位置
- 删除
Array.prototype.pop()
:从数组的最后删除元素Array.prototype.shift()
:从数组的最前删除元素delete 操作符
:删除数组指定位置元素
对于数组迭代的话,我们日常开发中常用的其实只有两种:
- 传统
for
循环:
forEach
循环:
在 JS
中存在一个特殊的数组概念,叫做 类数组对象。在 JS
中,所有的数组都拥有如下四个特性:
- ① 数组的
length
属性会在新元素加入时自动更新 - ② 设置
length
为更小的值会截断数组 - ③ 数组从
Array.prototype
继承有用的方法 - ④
Array.isArray()
对数组返回true
而类数组,虽然也具备 length
属性,但是却没有以上这四个特性。比如:arguments
。如果想要把类数组对象转化为数组对象,可以使用我们之前提到的 Array.from()
方法
第8章函数
函数包含参数的概念,参数分为 形参 和 实参 。其中 形参 表示 定义函数时指定的参数。 实参 表示 调用函数时传递的参数。在 JS
中实参和形参并 不需要 是一一对应的,同时函数调用也不对传入的实参进行任何类型检查。那么这样的一个动态的形式,在 JS
中就被分为了 5
个概念:
-
可选形参与默认值:这样的代码表示,如果没有传入
a
形参,那么a
默认为[]
-
剩余形参与可变长度实参列表:可以通过
...
的形式来获取所有的剩余实参。在这里rest = [10, 100, 2, 3, 1000, 4, 5, 6]
-
Arguments
对象:表示或许所有的实参,它是一个伪数组,可以通过Array.from
方法转化为真实数组 -
在函数调用中使用扩展操作符:在实参中可以使用扩展运算符,这表示把数组所有的元素作为一个一个的实参单独传入
-
把函数实参解构为形参:函数的形参可以直接进行解构
函数内部可以嵌套函数,如果 一个函数访问了其它函数作用域中才有的变量,那么这个函数可以叫做 闭包函数。闭包是在面试时的一个常见概念,需要大家能够掌握。
对于函数而言,它除了可以被调用之外,还拥有自己的 属性 和 方法。
-
属性:函数的属性有很多,咱们这里主要说三个
length
属性:形参的个数name
属性:定义函数时使用的名字prototype
属性:获取原型对象
-
方法
-
call()、apply()
:这两个是函数的典型方法。call()
和apply()
允许间接调用一个函数,就像这个函数是某个其他 对象 的方法一样,同时会把该函数中的this
修改为当前对象。 -
bind()
:在函数f
上调用bind()
方法并传入对象o
,则这个方法会返回一个新函数。同时它也会修改函数f
中的this
指向 -
toString()
方法:返回一个符合函数声明语句的字符串 -
Function()
构造函数:使用 Function() 构造函数可以用来 创建新函数
最后如果一个函数 接收一个函数参数,并返回一个新函数 的话,那么这个函数可以被叫做 高阶函数
-
第9章 类
首先 JS
中把 可以让一组对象在同一个原型对象中继承属性 的东西称之为 类。比如,我们可以简单的通过 Object.create() 创建实例
,那此时 Object
其实就可以被称为一个类。
在 ES6
之前,类以构造函数的形式进行呈现,所谓构造函数其实就是一个 首字母大写的普通函数:
因为它是一个普通函数,所以它既可以通过 构造函数 的形式,配合 new
进行使用。也可以直接调用使用。如果我们想要判断当前的函数是否是通过 new
关键字使用的,那么可以通过 new.target
来进行判定“:
通过构造函数得到的实例,可以利用 instanceof
关键字进行判定
在 ES6
之后,ES
推出了 class
的语法,利用 class
语法可以直接创建类,而不需要在像之前通过构造函数进行创建了。我们可以使用 class
重写 Range
类:
有了 class
之后,如果想要实现继承,那么就非常简单了,可以直接通过 extends 实现继承
:
利用 static
关键字,可以为类设置静态方法:静态方法是作为构造函数而非原型对象的属性定义的。
以上代码通过:Range.parse()
调用
因为 class
本质上依然是 原型继承 的机制,所以我们可以通过 prototype
属性来为已有的类添加方法:
视频出处:【(旧)一小时读完《JavaScript权威指南(第7版)》上】 https://www.bilibili.com/video/BV1Ts4y1N7S2/?share_source=copy_web&vd_source=a9f0fd4630ebe41da19ca2c83eb295e6
视频文档出处:https://juejin.cn/post/7211422882252947515
作者:LGD_Sunday