第一次完成重学前端JS篇收获不是特别多,再看一遍总结之后才发现受益良多。要多读勤于总结。
- String类型有最大长度,长度为2^53-1
- 对于0.1+0.2!==0.3的问题可以使用Math.abs(0.1+0.2<=Number.EPSILON)来解决,EPSILON时js的提供的最小精度常量
- Number、Boolean和String是两用的,当跟new搭配时,产生对象。直接调用,表示强制类型转换
- “ABC”.toString(),基本数据类型能调用方法是因为进行了装箱操作String,new Number(1)+2能进行运算是因为进行了拆箱操作,调用了valueOf()和toString()。
- JavaScript 中对象独有的特色是:对象具有高度的动态性,这是因为 JavaScript 赋予了使用者在运行时为对象添改状态和行为的能力。
- JavaScript有两类属性:
- 数据属性:他有四个特征
- value: 属性的值
- writable:决定属性能否被赋值
- enumerable:决定for in能否枚举该属性
- configurable:决定该属性能否被删除或者配置特征值
- 访问器属性:他也有四个特征
- get: 函数或 undefined,在取属性值时被调用
- set:函数或 undefined,在设置属性值时被调用
- enumerable:决定for in能否枚举该属性
- configurable:决定该属性能否被删除或者配置特征值
- 可以使用Object.getOwnPropertyDescriptor(ojb,key)获取属性的描述符
- 在创建对象时,也可以使用 get 和 set 关键字来创建访问器属性
var o = { get a() { return a },set a(val){a=val} };
- 数据属性:他有四个特征
- 基于类的描述对象的代表是java和C++,基于原型的描述对象的代表是js
- Object.create(),根据指定的原型创建新对象,原型可以是null
- Object.getPrototypeOf() 获得一个对象的原型
- Object.setPrototypeOf() 设置一个对象的原型
- 简易Object.create的实现:
Object.create = function(prototype){
var cls = function(){}
cls.prototype = prototype
return new cls
}
-
class 关键字和箭头运算符可以完全替代旧的 function 关键字,它更明确地区分了定义函数和定义类两种意图,虽然有点太绝对了,但是好像也没啥毛病。。。
-
JS的对象分类
- 宿主对象:由 JavaScript 宿主环境提供的对象,它们的行为完全由宿主环境决定。主要是游览器环境中的window对象,用户使用document.createElement创建的DOM对象也属于宿主对象。另外window对象的属性一部分是javaScript标准中规定的,另一部分是W3C标准规定的属性
- 内置对象:由 JavaScript 语言提供的对象。
- 固有对象:由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。比如:Infinity、NaN、undefined。eval、parseInt等函数,Array等构造器。
- 原生对象:可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象。
- 普通对象:由{}语法、Object 构造器或者 class 关键字定义类创建的对象,它能够被原型继承。
-
函数对象的定义是:具有[[call]]私有字段的对象,构造器对象的定义是:具有私有字段[[construct]]的对象。
-
JS的宏任务和微任务
- 宏任务:我们把宿主发起的任务称为宏任务
- 微任务:我们把JavaScript引擎发起的任务成为微任务
- js的事件循环底层C/C++代码简易代码:
while(TRUE) { // 等待,直到允许事件执行,返回该事件 r = wait(); execute(r); }
这里每次的执行过程,其实都是一个宏观任务。我们可以大概理解:宏观任务的队列就相当于事件循环。在宏观任务中,JavaScript 的 Promise 还会产生异步代码,JavaScript 必须保证这些异步代码在一个宏观任务中完成,因此,每个宏观任务中又包含了一个微观任务队列。
-
Promise
- 它的总体思想是,需要进行 io、等待或者其它异步操作的函数,不返回真实结果,而返回一个“承诺”,函数的调用方可以在合适的时机,选择等待这个承诺兑现(通过 Promise 的 then 方法的回调)。
-
闭包
- 绑定的执行环境的函数
- 闭包的组成部分:
- 环境部分
- 环境:函数的词法环境(执行上下文的一部分
- 标识符列表:函数中用到的未声明的变量
- 表达式部分:函数体
- 环境部分
- 实际上 JavaScript 中跟闭包对应的概念就是“函数”。
-
执行上下文
- JavaScript 标准把一段代码(包括函数),执行所需的所有信息定义为:“执行上下文”。
- 执行上下文在 ES3 中,包含三个部分:
- scope:作用域,也常常被叫做作用域链。
- variable object:变量对象,用于存储变量的对象。
- this value:this 值。
- 在 ES5 中,我们改进了命名方式,把执行上下文最初的三个部分改为下面这个样子:
- lexical environment:词法环境,当获取变量时使用。
- variable environment:变量环境,当声明变量时使用。
- this value:this 值。
-
var声明与赋值
- 函数作用域穿透{}
- 为了模拟块级作用域产生了立即执行函数
- 立即执行函数的写法
// 因为function是函数声明关键字,为了立即执行要在外面加(),为了避免语法错误要在前面加‘;’
;(function(){ var a; //code}());
// 推荐,因为不用加;
void function(){ var a; //code}();
-
函数的种类
- 普通函数function
- 箭头函数 =>
- class类
- class类里的函数
- 生成器函数function *
- async函数
-
this
- 是函数调用时使用的引用,决定了函数执行时刻的this值
- 实际上从运行的角度来对来看,this跟面向对象毫无关联,他是与函数调用时使用的表达式相关
- this关键字的机制:
- 在javaScript的标准中,为函数规定了用来保存定义时的上下文的私有属性[[Environment]]
- 当一个函数执行时,会创建一条新的执行环境记录(outer lexical environment),记录的外层词法环境会被设置成函数的[[Environment]]
- javaScript用一个栈来保存执行上下文,每个栈里面又是一个链表,保存它的lexical environment和outer lexical environment
- javaScript标准定义了[[thisMode]]私有属性:有三个值
- lexical:表示从上下文中找this,对应了箭头函数
- global:表示当this为undefined时,取全局对象,对应了普通函数
- strict:当严格模式时使用,this严格按照调用时传入的值,可能为null或者undefined
-
Completion Record用于描述异常、跳出等语句的执行过程,标记语句执行的完成状态,我们用一个类型来表示就是Completion Record。
- Completion Record表示一个语句执行完之后的结果,他有三个字段:
- [[type]]表示完成的类型,有break,continue,return,throw和normal
- [[value]]表示语句的返回值,如果没有就empty
- [[target]]表示语句的目标,通常是一个javsScript标签
- 语句:
- 普通语句
- 声明式语句
- var 声明
- let 声明
- const 声明
- 函数声明
- 类声明
- 表达式语句
- 空语句
- with语句
- debugger语句
debugger 语句debugger 语句的作用是:通知调试器在此断点。在没有调试器挂载时,它不产生任何效果。
- 声明式语句
- 语句块
- 控制型语句
- if
- switch
- for
- for
- for of
- for in
- for-await-of
- while
- while
- do while
- continue
- break
- return
- throw
- try
- 带标签的语句
- 普通语句
- 普通语句执行后会得到type为normal的Completion Record,JavaScript遇到这样的语句会继续执行下一条语句,这些语句只有表达式会产生[[value]]。
游览器console控制台里输入
i = 1
输出1 ,而var i = 1
输出undefined。Chrome 控制台显示的正是语句的 Completion Record 的[[value]]。 - 因为finally中的内容必须保证执行,所以try/catch执行完毕,即使得到的结果是非normal型的完成记录,也必须执行finally,而finally执行也得到了非normal的记录,则会使finally中的记录作为整个try结构的结果。
- 带标签的语句
- 事实上,任何语句都可以加标签,但是几乎没有作用,可以用于
break 标签;
跳出多层循环
- 事实上,任何语句都可以加标签,但是几乎没有作用,可以用于
- Completion Record表示一个语句执行完之后的结果,他有三个字段:
-
词法
- JavaScript的文法包括词法和语法
- 词法的最小语义单元使token,可以认为是标记或者词
- 分类:
- WhiteSpace 空白字符
- LineTerminator 换行符
- Comment 注释
- Token 词
- IdentifierName,标识符名称,变量名和关键字都属于此类
- Punctuator 符号,运算符和大括号等符号
- NumericLiteral 数字直接量
- StringLiteral 字符串直接量
- Template 字符串模板,用``括起来的直接量
- 12.toString()报错和12 .toString()不报错的原因
- 12.toString()的toString()被当成12数字的小数部分,执行错误报错
-
一定要加分号,否则容易导致歧义的情况
- 以括号开头
- 以数组开头
- 以正则表达式开头
- 以模板字符串开头
- 加号减号开头
-
脚本和模块
- 脚本具有主动性、模块是等待被调用的库
- 脚本和模块的区别其实只是export 和import 的区别
- script标签如果要引入模块,要加上
type = “module”
import "mod"; //引入一个模块
- 注意:任何被引入的模块,它的代码都会从头到尾执行一次
- 直接 import 一个模块,只是保证了这个模块代码被执行,引用它的模块是无法获得它的任何信息的。
import v from "mod"; //把模块默认的导出值放入变量v
- 指令序言
‘use strict'
——JavaScript 标准中规定的唯一一种指令序言,作用是如果方法的直接调用对象是null,则方法内的this也为null。否则为全局对象window
-
表达式
- PrimaryExpression主要表达式,一般是各种直接量,数字、字符串、函数或者对象等等。
- MemberExpression 成员表达式,用于访问成员比如a.b,访问成员的表达式
- NewExpression NEW 表达式,类似new Class()的表达式
- CallExpression 函数调用表达式,比如a.b(),调用方法的表达式
- LeftHandSideExpression 左值表达式,左值表达式就是可以放到等号左边的表达式。例如
a() = b;
- AssignmentExpression 赋值表达式, 赋值语句+=也算在内
- Expression 表达式,用
,
元素运算符连接的赋值表达式
-
右值表达式
- 能够出现在赋值表达式右边的叫做右值表达式
- 更新表达式,比如++a,–a等
- 一元表达式,delete void typeof +a -a !a ~a等等、
- 乘方表达式,2**30
- 乘法表达式、加法表达式
- 移位表达式 >> <<
- 关系表达式 > <
- 相等表达式 ===
- 位运算表达式 & | ^
- 逻辑与表达式和逻辑或表达式 && ||
- 条件表达式 a?b:c