ES6学习笔记(二)

103 阅读10分钟

Symbol

  1. 表示独一无二的值
  2. Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分
  3. Symbol 值作为对象属性名时,不能用点运算符。
  4. 在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
  5. Object.getOwnPropertySymbols() 遍历 symbol
  6. Symbol.for(),Symbol.keyFor()
    1. Symbol.for():接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。
    2. Symbol.keyFor():返回一个已登记的 Symbol 类型值的 key。
  7. Symbol.isConcatSpreadable,表示该对象用于 Array.prototype.concat()时,是否可以展开。
    1. 数组对象的这个值默认为 undefined,默认是展开的,为 true 时也为展开
    2. 类数组对象的这个值默认是不展开的,可能也是 undefined,只有为 true 时可以展开

Set 数据结构

  1. 向 set 结构中添加数组、数值、对象等不会添加相同的对象
    • 值的集合、运行存储任意类型的唯一值
  2. Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。
  3. 应用场景
    1. 去重
    2. 取交集、并集等

WeakSet

  1. 结构与 Set 类似,也是不重复的值的集合。
  2. WeakSet 的成员只能是对象,而不能是其他类型的值。
  3. WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。
  4. WeakSet 不可遍历。

Map 数据结构

  1. 由于对象只接受字符串作为键名,为了解决键名只能为字符串的问题,ES6 提供了 Map。
  2. 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
  3. 需要对除字符串以外的数据类型进行映射的时候,Map 就可以派上用场。

WeakMap

  1. WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
  2. WeakMap 的键名所指向的对象,不计入垃圾回收机制。WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。
  3. WeakMap 的专用场合就是,它的键所对应的对象,可能会在将来消失。

代理 Proxy

  1. 元编程
  2. 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
    var proxy = new Proxy(target, handler);
    
    new Proxy 表示生成一个实例,target 表示要拦截的对象,handle 定制拦截行为
  3. Proxy.revocable()方法返回一个可取消的 Proxy 实例。
    • Proxy.revocable()的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
  4. 在 Proxy 代理的情况下,目标对象内部的 this 关键字会指向 Proxy 代理

Promise

  1. 异步编程的一种方案,为了解决回调地狱

  2. 特点:

    1. 对象的状态不受外部影响。只受异步操作结果影响
    2. 一旦状态改变就不会再变,任何时候都能拿到这个结果 事件的特点是,如果你错过了它,再去监听,是得不到结果的
  3. 状态:pending、rejected 和 fullfilled

    1. resolved 表示已解决,当异步请求返回结果(不成功 rejected 或成功 fullfilled)时
    2. Promise.resolve() Promise.reject()
      • Promise.resolve()能够将现有对象转换为 Promise 对象
      • Promise.reject()返回一个 Promise 实例,但该实例的状态为 rejected
  4. .then()、.catch()和.finally()

  5. 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);
    });
    
  6. Promise.race()

async await

  1. async 会返回一个 Promise,return 的数据会成为 then 的参数
  2. await 在等待他后面的表达式或 Promise 或其他的出结果,如果后面只是个值会立即返回
  3. async 和 await 的好处
  4. 用 Promise 来优化异步处理,用 async 和 await 来优化 Promise
  5. 目前 await 只能用于 async 函数内部

Class

  1. Class 类似于函数

    class Point {
      constructor(a, b) {
        this.a = a;
        this.b = b;
      }
    
      toString() {
        return "(" + this.a + "," + this.b + ")";
      }
    }
    // 生成实例
    var p = new Point();
    
  2. 类的内部所有定义的方法,都是不可枚举的

  3. constructor 方法是类的默认方法,生成实例时会自动调用这个方法。一个类必须有 constructor 方法,否则就会自动生成一个空方法

    1. 属性也可以在顶部定义,不在 constructor 里定义
  4. 默认返回实例对象(即 this),完全可以指定返回另外一个对象

  5. 类必须用 new 调用

  6. 在“类”的内部可以使用 get 和 set 关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

    class Point {
      constructor() {
        // ...
      }
      get prop() {
        return "getter";
      }
      set prop(value) {
        console.log("setter: " + value);
      }
    }
    

    prop 属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了

  7. 类和模块内部是严格模式;类不存在变量提升

静态方法

  • static
  • 方法前加上“static”,就不会被实例继承

实例属性、类属性、原型属性

class Point {
  constructor(a) {
    // 实例属性:新建一个实例就会有自己的属性
    this.a = a;
    // 类属性:只能通过调用类来获取
    Point.b = 0;
  }
}
// 原型属性:实例共享的属性
Point.prototype.c = "a";

extends 继承

super,指向当前对象的原型对象

  1. 只要写了 constructor 方法就必须使用 super 继承父类的属性,如果不写 constructor 方法,会自动添加

  2. 可以使用 super 继承父类的方法

    class B {
      say() {}
    }
    class A extends B {
      // constructor() {
      //   super();
      // }
      // 自动添加
      constructor(...args) {
        super(...args);
      }
    
      see() {
        return super.say();
      }
    }
    
  3. 在子类的构造函数中,只有调用 super 之后,才可以使用 this 关键字,否则会报错

  4. 父类的静态方法,也会被子类继承

super

  1. super 作为函数调用时,代表父类的构造函数 super();
  2. super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

module

  1. 模块自动采用严格模式
  2. import 引入,export 输出;export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。
  3. 尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量
  4. export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
    1. 意思就是必须有一个接口来对应这个模块里的变量,一般接口名=变量名
  5. import 不是 require 函数那种的动态加载,有个提案 import()函数可以动态加载
    export { firstName, lastName, year };
    import { firstName, lastName, year } from "./profile.js";
    import * from "./xxx.js";
    
  6. export default 在模块中只能有一个
  7. 模块顶层使用 this 指向 undefined,而不是 window
  8. import 是引用,是只读的

异步加载 script 标签

  1. defer 和 async
  2. defer 是“渲染完再执行”,async 是“下载完就执行”
  3. 如果有多个 defer 脚本,会按照它们在页面出现的顺序加载,而多个 async 脚本是不能保证加载顺序的。
  4. 浏览器加载模块
    <!-- 默认defer -->
    <script type="module" src="./foo.js"></script>
    

node.js 中的 CommonJS 与 ES6 的模块

  1. 差异:
    1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
    2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  2. 第二个差异是因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
  3. node.js 使用 ES6 模块
    1. .mjs 文件总是以 ES6 模块加载,.cjs 文件总是以 CommonJS 模块加载,.js 文件的加载取决于 package.json 里面 type 字段的设置。

循环加载

  1. CommonJS 模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存

函数式编程

  1. 柯里化
  2. 函数合成
  3. 参数倒置
  4. 执行边界
  5. 。。。

函数式编程

  1. 函数式编程
    1. 与面向对象编程(Object-oriented programming)和过程式编程(Procedural programming)并列的编程范式
    2. 最主要的特征是,函数是第一等公民
    3. 强调将计算过程分解成可复用的函数,典型例子就是 map 方法和 reduce 方法组合而成 MapReduce 算法
    4. 只有纯的、无副作用的函数才是合格的函数

其他编程

  1. 命令式编程专注于怎么做
  2. 声明式编程和函数式编程专注于做什么
    1. SQL 语言是典型的声明式编程

AJAX

异步编程

  1. 在处理请求时可以同时处理其他任务
  2. 阻塞:有时一些进行密集运算的任务会耗费大量时间,而 JavaScript 的单线程意味着只能等待这个任务完成才能进行下一个。为了解决这个问题,就有了异步编程

set 和 get 方法

  1. set 方法:将对象属性与函数进行绑定,当改变属性值时,对应函数被执行
  2. get 方法:将对象属性与函数进行绑定,当属性被访问时,对应函数被执行

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

映射

就是一对一,给对象起一个别名,找到别名就可以找到数据

setInterval 和 setTimeout

  1. setTimeout()在指定的时间后执行一段代码.
  2. setInterval()以固定的时间间隔,重复运行一段代码.
  3. 区别
    1. setTimeout()方法只运行一次,也就是说当达到设定的时间后就出发运行指定的代码,运行完后就结束了,如果还想再次执行同样的函数,可以在函数体内再次调用 setTimeout(),可以达到循环调用的效果。
    2. setInterval()是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,是真正的定时器。

内存泄漏

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

垃圾回收机制