vlambda博客
学习文章列表

【趣读系列】JavaScript高级程序设计(3)


哈罗大家好,我是永不加群永不卖课只想跟大家一起看书看源码的猿油站


这次跟大家一起来啃 前端圣经级 字典级工具书的翘楚前端发展见证者陪伴一代又一代前端人砥砺前行 厚度高达3厘米 自己翻基本翻两页就不想翻 的JS红宝书

JavaScript高级程序设计



第三章 - 语言基础

概念:

任何语言的核心最基础层面一定包括:语法,操作符,数据类型,以及内置功能

语法:

ECMAScript的语法很大程度上借鉴了`C`语言和其他类`C`语言,例如`java`,`perl`

大小写:

ECMAScript中的一切都是区分大小写的,无论是变量操作符还是函数名

标识符:

标识符 :所谓标识符,就是变量函数或函数参数的名称,标识符有以下规则:

  1. 第一个字符必须是字母,下划线或者美元符号($),剩下的字符可以是字母,数字,下划线,美元符号

  2. 标识符中的字母可以ASCII中的特殊字符但是不推荐

  3. 标识符推荐使用驼峰命名法

  4. 关键字,保留字无法当作标识符

注释:

html中的注释是<-- -->js中的注释是// 或者是 /* */

严格模式:

ES5中增加严格模式,是一种不同的Javascript解析和执行模型,通过在脚本开头或者函数体内部增加use strict字符这个预处理指令,开启严格模式,一些不规则的(ECMA3)写法在这个模式会被处理,抛出安全错误

关于分号:

ECMAScript语句以结尾,意味解析器确定语句在哪里结束(不是必须)但是推荐,推荐的原因如下:

  1. 避免输入内容不完整

  2. 便于开发者通过删除空行来压缩代码

  3. 某些情况下能够提升性能,因为解释器会尝试在合适的位置补上分号以纠正语法错误

关于 花括号{}

多条语句合并到一个代码块,通过花括号{}标识起始和结束,if条件语句在执行一条代码块时可以省略花括号,但是不推荐

关键字和保留字:

ECMAScript保留了例如控制语句特定操作,系统属性等一系列不允许自定义为标识符的名称,具体内容如下:

break do in typeof case else instanceof var catch export new void class extends return while const finally super with continue for switch yield debugger function this default if hrow delete import try

还有一些为来可能会用到的保留字enum

同时严格模式也会有更多严重的关键字 implements package publicinterface protected static let private

模块中保留的:

await

关于变量

ECMAScript变量是松散类型,变量可以保存任何的数据类型, 每个变量只是用于保存任意值的命名占位符,有三个关键字可以声明变量var ,let,const,其中varECMAScript所有版本中可以使用,而constlet只能在es6及更新的版本中使用

使用var声明变量需要注意

  1. var声明的变量是松散类型

  2. var声明变量的作用域是函数作用域或者是全局作用域,省略var关键字的时候会在全局作用域下创建一个全局变量

  3. var声明提升,所有变量声明都会拉到作用域的顶部(函数/全局)所有反复多次声明同名变量也没有关系

使用let声明变量需要注意

  1. let声明变量的也是松散类型

  2. let声明变量的作用域是块级作用域,并且不允许同一个作用域重复声明,冗余声明

  3. 由于let的块级作用域特性,在循环体中,如果使用let可以避免循环体外的变量污染,同时也可以保证循环体内部代码块值的正确性

下面是一个例子

```
在使用 var 的时候,最常见的问题就是对迭代变量的奇特声明和修改:
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时
逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
而在使用 let 声明迭代变量时,JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。
每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循
环执行过程中每个迭代变量的值。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4
```
  1. 使用letvar声明同名变量同样会报错,声明冗余

  2. 使用let会出现暂时性死区,因为let不会作用域提升,所以在let声明变量之前的所有同名变量引用会抛出 Reference Error,这个声明之前的不能使用该变量名的区域叫做"暂时性死区"

  3. 由于3,4的原因在作用域可能会存在不确定该变量是否已经let声明的情况,如果已声明重复声明会抛出错误,未声明直接使用也会抛出引用错误

  4. 全局声明,在全局作用域使用var声明会自动成为window对象的属性,但是使用let不会成为window对象的属性

使用const 需要注意:

  1. 使用constlet行为基本相同,但是创建时必须初始化变量值,并且在尝试修改const声明变量的值会导致运行时报错

const person = {}; 
person.name = 'Matt'; // ok 

声明风格及最佳实践

  1. 不推荐使用var,有助于提升代码质量,因为变量有了明确的作用域,声明位置

  2. const优先,let次之,及时区分常量和变量


常见面试题/自测题

  1. Javascript中变量声明是区分大小写的吗?Typeoftypeof有区别吗?

  2. Javascript中的标识符规则

  3. 说说JavaScript中的严格模式,跟普通模式有什么区别

  4. 说说var的变量提升及原理

  5. 说说varlet的区别

  6. 什么是暂时性死区

  7. 说说 let在循环体中和var的区别

  8. constlet的区别

  9. 使用const声明变量一定不能修改值吗?

  10. var声明变量在循环体中的奇怪表现及原因

面试题/自测题答案

  1. Javascript中是区分大小写的;typeofjavascript保留字,系统函数,一元运算,返回值是一个字符串,说明运算数的类型;Typeof没有特殊含义,是一个可用的标识符名,可以用来声明函数或变量

  2. 标识符规则:

  • 使用字符串或者美元符号或者下划线开头,后面可以是数字,ASCII字符,美元符号或者下划线,推荐使用驼峰命名法
  1. 严格模式是一种特殊的解析和执行模式,在代码开头或者函数开头使用use strict字符标识,跟普通模式的却别是会在运行和解析时把一些不规范的语法,抛出安全粗欧文

  2. 使用var声明变量时,在预编译阶段,会在声明函数作用域或者全局作用域,自动补全一句声明语句,如果在赋值之前引用该值都会返回默认值undefined,并且由于预编译的变量提升,多条重复的声明会覆盖。

  • 原理: JS也是一种编译语言,在代码执行之前,解释器会进行预编译,在预编译时,使用 var关键字进行变量声明会提升到作用域顶部
  1. 区别:
  • var声明变量会有变量提升,let声明变量没有变量提升

  • var声明变量的作用域是最近的函数作用域或者全局作用域,使用let声明变量的作用域是最近的块级作用域

  • let声明由于不会变量提升,会出现暂时性死区

  • let声明不允许冗余声明,并且不能跟var声明重复声明

  • 全局声明时var关键字声明的变量会自动成为window对象的属性,let声明的全局变量不会

  1. 暂时性死区指的是,在使用let声明变量时,由于不会预编译时变量提示,所以在声明该变量之前对该变量名的所有引用都会抛出引用错误,这个区域叫做暂时性死区,在声明之前不允许引用,所有引用都会报错

  2. 在循环体中,由于let的作用域是块级,每一次循环的时候都会开辟新的块级作用域空间,所以每一次循环的时候都会创建新的变量。

  3. 区别:

  • constlet的行为基本一致,但是在声明时必须初始化该变量的值,并且不允许修改 const声明值的引用地址

  • var声明的变量,for 循环中定义的迭代变量会渗透到全局
for (var i = 0; i < 5; ++i) { 
 // 循环逻辑 

console.log(i); // 5 
  • 对迭代变量的奇特声明和修改
for (var i = 0; i < 5; ++i) { 
 setTimeout(() => console.log(i), 0) 

// 你可能以为会输出 0、1、2、3、4 
// 实际上会输出 5、5、5、5、5 

所有的原因都是使用var声明变量的变量提升特性和var变量的作用域特性。