Symbol
- 表示独一无二的值
- Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分
- Symbol 值作为对象属性名时,不能用点运算符。
- 在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
- Object.getOwnPropertySymbols() 遍历 symbol
- Symbol.for(),Symbol.keyFor()
- Symbol.for():接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
- Symbol.keyFor():返回一个已登记的 Symbol 类型值的 key。
- Symbol.isConcatSpreadable,表示该对象用于 Array.prototype.concat()时,是否可以展开。
- 数组对象的这个值默认为 undefined,默认是展开的,为 true 时也为展开
- 类数组对象的这个值默认是不展开的,可能也是 undefined,只有为 true 时可以展开
Set 数据结构
- 向 set 结构中添加数组、数值、对象等不会添加相同的对象
- 值的集合、运行存储任意类型的唯一值
- Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。
- 应用场景
- 去重
- 取交集、并集等
WeakSet
- 结构与 Set 类似,也是不重复的值的集合。
- WeakSet 的成员只能是对象,而不能是其他类型的值。
- WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。
- WeakSet 不可遍历。
Map 数据结构
- 由于对象只接受字符串作为键名,为了解决键名只能为字符串的问题,ES6 提供了 Map。
- 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
- 需要对除字符串以外的数据类型进行映射的时候,Map 就可以派上用场。
WeakMap
- WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
- WeakMap 的键名所指向的对象,不计入垃圾回收机制。WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。
- WeakMap 的专用场合就是,它的键所对应的对象,可能会在将来消失。
代理 Proxy
- 元编程
- 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
new Proxy 表示生成一个实例,target 表示要拦截的对象,handle 定制拦截行为var proxy = new Proxy(target, handler); - Proxy.revocable()方法返回一个可取消的 Proxy 实例。
- Proxy.revocable()的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
- 在 Proxy 代理的情况下,目标对象内部的 this 关键字会指向 Proxy 代理
Promise
-
异步编程的一种方案,为了解决回调地狱
-
特点:
- 对象的状态不受外部影响。只受异步操作结果影响
- 一旦状态改变就不会再变,任何时候都能拿到这个结果
事件的特点是,如果你错过了它,再去监听,是得不到结果的
-
状态:pending、rejected 和 fullfilled
- resolved 表示已解决,当异步请求返回结果(不成功 rejected 或成功 fullfilled)时
- Promise.resolve() Promise.reject()
- Promise.resolve()能够将现有对象转换为 Promise 对象
- Promise.reject()返回一个 Promise 实例,但该实例的状态为 rejected
-
.then()、.catch()和.finally()
-
Promise.all()中的任何一个 Promise 返回 rejected,所有都为 rejected
const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, "foo"); }); Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); }); -
Promise.race()
async await
- async 会返回一个 Promise,return 的数据会成为 then 的参数
- await 在等待他后面的表达式或 Promise 或其他的出结果,如果后面只是个值会立即返回
- async 和 await 的好处
- 用 Promise 来优化异步处理,用 async 和 await 来优化 Promise
- 目前 await 只能用于 async 函数内部
Class
-
Class 类似于函数
class Point { constructor(a, b) { this.a = a; this.b = b; } toString() { return "(" + this.a + "," + this.b + ")"; } } // 生成实例 var p = new Point(); -
类的内部所有定义的方法,都是不可枚举的
-
constructor 方法是类的默认方法,生成实例时会自动调用这个方法。一个类必须有 constructor 方法,否则就会自动生成一个空方法
- 属性也可以在顶部定义,不在 constructor 里定义
-
默认返回实例对象(即 this),完全可以指定返回另外一个对象
-
类必须用 new 调用
-
在“类”的内部可以使用 get 和 set 关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class Point { constructor() { // ... } get prop() { return "getter"; } set prop(value) { console.log("setter: " + value); } }prop 属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了
-
类和模块内部是严格模式;类不存在变量提升
静态方法
- static
- 方法前加上“static”,就不会被实例继承
实例属性、类属性、原型属性
class Point {
constructor(a) {
// 实例属性:新建一个实例就会有自己的属性
this.a = a;
// 类属性:只能通过调用类来获取
Point.b = 0;
}
}
// 原型属性:实例共享的属性
Point.prototype.c = "a";
extends 继承
super,指向当前对象的原型对象
-
只要写了 constructor 方法就必须使用 super 继承父类的属性,如果不写 constructor 方法,会自动添加
-
可以使用 super 继承父类的方法
class B { say() {} } class A extends B { // constructor() { // super(); // } // 自动添加 constructor(...args) { super(...args); } see() { return super.say(); } } -
在子类的构造函数中,只有调用 super 之后,才可以使用 this 关键字,否则会报错
-
父类的静态方法,也会被子类继承
super
- super 作为函数调用时,代表父类的构造函数 super();
- super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
module
- 模块自动采用严格模式
- import 引入,export 输出;export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。
- 尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量
- export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
- 意思就是必须有一个接口来对应这个模块里的变量,一般接口名=变量名
- import 不是 require 函数那种的动态加载,有个提案 import()函数可以动态加载
export { firstName, lastName, year }; import { firstName, lastName, year } from "./profile.js"; import * from "./xxx.js"; - export default 在模块中只能有一个
- 模块顶层使用 this 指向 undefined,而不是 window
- import 是引用,是只读的
异步加载 script 标签
- defer 和 async
- defer 是“渲染完再执行”,async 是“下载完就执行”
- 如果有多个 defer 脚本,会按照它们在页面出现的顺序加载,而多个 async 脚本是不能保证加载顺序的。
- 浏览器加载模块
<!-- 默认defer --> <script type="module" src="./foo.js"></script>
node.js 中的 CommonJS 与 ES6 的模块
- 差异:
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- 第二个差异是因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
- node.js 使用 ES6 模块
- .mjs 文件总是以 ES6 模块加载,.cjs 文件总是以 CommonJS 模块加载,.js 文件的加载取决于 package.json 里面 type 字段的设置。
循环加载
- CommonJS 模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存
函数式编程
- 柯里化
- 函数合成
- 参数倒置
- 执行边界
- 。。。
函数式编程
- 函数式编程
- 与面向对象编程(Object-oriented programming)和过程式编程(Procedural programming)并列的编程范式
- 最主要的特征是,函数是第一等公民
- 强调将计算过程分解成可复用的函数,典型例子就是 map 方法和 reduce 方法组合而成 MapReduce 算法
- 只有纯的、无副作用的函数才是合格的函数
其他编程
- 命令式编程专注于怎么做
- 声明式编程和函数式编程专注于做什么
- SQL 语言是典型的声明式编程
AJAX
异步编程
- 在处理请求时可以同时处理其他任务
- 阻塞:有时一些进行密集运算的任务会耗费大量时间,而 JavaScript 的单线程意味着只能等待这个任务完成才能进行下一个。为了解决这个问题,就有了异步编程
set 和 get 方法
- set 方法:将对象属性与函数进行绑定,当改变属性值时,对应函数被执行
- get 方法:将对象属性与函数进行绑定,当属性被访问时,对应函数被执行
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
映射
就是一对一,给对象起一个别名,找到别名就可以找到数据
setInterval 和 setTimeout
- setTimeout()在指定的时间后执行一段代码.
- setInterval()以固定的时间间隔,重复运行一段代码.
- 区别
- setTimeout()方法只运行一次,也就是说当达到设定的时间后就出发运行指定的代码,运行完后就结束了,如果还想再次执行同样的函数,可以在函数体内再次调用 setTimeout(),可以达到循环调用的效果。
- setInterval()是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,是真正的定时器。
内存泄漏
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。