js基础:es6 中需要注意的一些点

es6 的一些需要额外注意的点

  1. let && const

    • 拥有块级作用域
    • 不可重复声明
    • 暂时性死区 (作用域内声明前, 不可用, 报错)
    • 未声明前, typeof 也是直接报错, 但 typeof 一个为定义的变量不会报错, 输出 undefined (typeof 不再安全)
    • const,声明必须赋值 (并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动)
    • let、const、class 声明的全局变量,不属于顶层对象的属性。从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
    • globalThis 全局对象(提案)
  2. 解构

    • 字符串也可以解构赋值。 const [a, b, c, d, e] = ‘hello’;
    • 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
    1
    2
    let { toString: s } = 123
    s === Number.prototype.toString
  3. 字符串方法

    • includes(), startsWith(), endsWith(), padStart(),padEnd(), tirmStart(), tirmEnd()
  4. 数字

    • Number.isFinite(), Number.isNaN() 与 isNaN() 区别, isNaN()会先转换成数字, 如 isNaN(‘a’) //true
    • Number.isInteger(), Number.isSafeInteger()
    • Math.sign 方法用来判断一个数到底是正数、负数、还是零
    • 指数运算符(**)
  5. 函数

    • length 属性 , 含义是,该函数预期传入的参数个数, 指定了默认值后,该参数不被统计
    • rest 参数(形式为…变量名),rest 参数之后不能再有其他参数
    • name 属性, 函数名 var f = function () {}; // es5 f.name=> “” // es6 f.name=> “f”
    • 箭头函数内的 this 对象,就是定义时所在的对象
    • 箭头函数不可以当作构造函数
    • 箭头函数不可以使用 arguments 对象
    • 箭头函数不能用作 Generator 函数
  6. 数组

    • 扩展运算符, 复制数组, 合并数组
    • 与解构赋值结合 const [first, …rest] = [1, 2, 3, 4, 5];
    • 将字符串转为真正的数组 […’hello’]
    • Iterator
    • Array.from 将两类对象转为真正的数组:类似数组的对象和可遍历的对象, Array.from(Set)
    • Array.of 方法用于将一组值,转换为数组 Array.of(3, 11, 8)
    • find() 和 findIndex()
    • fill() // let a = []; a.length =100; a.fill(1) // [1,1,1,1,….100 个 1]
    • includes()
    • flat() / flatMap() 扁平化数组
    • 数组的空位, ES6 则是明确将空位转为 undefined // Array(3) // [, , ,]
  7. 对象

    • Object.getOwnPropertyNames 包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)
    • Object.getOwnPropertySymbols 返回一个数组,包含对象自身的所有 Symbol 属性的键名
    • Reflect.ownKeys 返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
    • 扩展运算符 // {…{b:2}, a: 1} //{b: 2, a: 1}
    • Object.is 跟 === 一样
    • Object.assign(target, source1, source2) 将源对象(source)的所有可枚举属性,复制到目标对象(target)(浅拷贝)
    • Object.getPrototypeOf() => proto
    • Object.keys(),Object.values(),Object.entries() (键值对数组)
  8. set / map

    • 在 Set 内部,两个 NaN 是相等
    • Map 的遍历顺序就是插入顺序
  9. promise

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //	加载图片
    const preloadImage = function (path) {
    return new Promise(function (resolve, reject) {
    const image = new Image()
    image.onload = resolve
    image.onerror = reject
    image.src = path
    })
    }
    • Promise.all / Promise.race
  10. Iterator

    • 任何数据结构只要部署 Iterator 接口,就可以完成遍历操作 for…of
    • 对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的
    • 获取 Iterator
      1
      2
      3
      4
      let iter = [1, 2, 3][Symbol.iterator]()
      iter.next() //{value: 1, done: false}
      iter.next() //{value: 2, done: false}
      iter.next() //{value: 3, done: true}
  • 调用 Iterator 接口的场合 => 解构赋值, 扩展运算符, yield* , for…of, Array.from(),Map(), Set(), Promise.all / Promise.race
  1. async

    • async 函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部 then 命令的语法糖
    • async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数
    • 没有 return , 返回 resolve(undefined)
    • async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    async function f() {
    throw new Error('出错了')
    }

    f()
    .then((v) => console.log(v))
    .catch((e) => {
    console.log(e)
    })
  2. await 命令只能出现在 async 函数内部,否则都会报错

13.类 注意的几个点 :

  • class中定义的方法, 均为原型方法
1
2
3
4
class F {
say() {}
}
F.prototype.hasOwnProperty('say') //true
  • class 中定义的属性, 均为实例属性, 而非在原型上, 并且构造函数中定义相同属性会覆盖class中的定义
1
2
3
4
5
6
7
8
9
class W {
a = 1
constructor() {
this.a = 2
}
}
let w = new W()
w.hasOwnProperty('a') //true
w.a // 2
  • 类本身指向构造函数
1
Object.getPrototypeOf(w).constructor === W
  • class 没有写构造函数, 会自动创建一个, 并返回this
  • es5不同的是, 类中定义的方法是不可枚举的, es5prototype写法可以
1
2
3
4
5
6
7
8
9
10
//class
class F {
say() {}
}
Object.keys(F.prototype) // []

// es5
function G() {}
G.prototype.say = function () {}
Object.keys(G.prototype) // ['say']
  • __proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,我们可以使用 Object.getPrototypeOf
  • static修饰的方法不会被实例继承, 静态方法, 只能被类调用, 可以与实例方法重名
1
2
3
4
5
6
7
8
9
10
11
class H {
static say() {
console.log(1)
}
say() {
console.log(2)
}
}
let h = new H()
h.say() // 2
H.say() // 1
  • 使用extends继承时, 若子类显式地写了构造函数, 那么构造函数 中必须调用super(), 子类未显式写构造函数则不用
  • class中可以写get, set
1
2
3
4
5
6
7
8
class K {
get a() {
return this.b
}
set a(val) {
this.b = val
}
}