ECMAScript 6 学习笔记

ECMAScript  6 教程参考: https://wangdoc.com/es6/intro.html

 

1. let和const命令

      let 命令 : 用来声明变量, 只在let命令所在的代码块内有效

      const命令 : 用来声明只读的常量, 必须立即初始化, 值不能改变, 只在const命令所在的代码块内有效

      不存在变量提升 : 声明的变量一定要在声明后使用, 否则报错

      不允许重复声明 : 相同作用域, 不允许重复声明同一个变量

      声明变量的方法 : ES5: var, function;  ES6: let, const, import, class

      声明的全局变量, 不属于顶层对象的属性

2. 变量的解构赋值

     ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

     用途 : 

            (1)交换变量的值

let x = 1;
let y = 2;

[x, y] = [y, x];

            (2)从函数返回多个值

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

            (3)函数参数的定义

// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

            (4)提取JSON数据

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

             (5)函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

              (6)遍历Map结构

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

             (7)输入模块的指定方法

const { SourceMapConsumer, SourceNode } = require("source-map");

3. 字符串的扩展

  • 遍历器接口
for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"
  • 模板字符串

       增强版字符串, 用反引号(`)标识, 可以当做普通字符串, 多行字符串, 在字符串中嵌入变量

  • 实例方法

        includes()  是否找到参数字符串

        startsWith()  参数字符串是否在原字符串的头部

        endsWith()  参数字符串是否在原字符串尾部

        repeat(n)  将原字符串重复n次

        padStart()  不够指定长度, 则使用指定字符串在头部补全

        padEnd()   不够指定长度, 则使用指定字符串在尾部补全

        trimStart()  消除字符串头部空格

        trimEnd()   消除字符串尾部空格

        replaceAll()  一次替换所有匹配

4. 数值的扩展

  • 常量

       EPSILON   最小误差范围

       MAX_SAFE_INTEGER   最大安全整数

       MIN_SAFE_INTEGER   最小安全整数

  • Number方法

       isFinite() 是否为有限的

       isNaN()  是否为NaN

       isInteger()  是否为整数

       isSafeInteger()  是否在最大和最小安全整数内

  • Math方法

       trunc()  去除一个数的小数部分

       sign()  判断一个数是正数, 负数, 还是0

       cbrt()  计算一个数的立方根

  • BigInt

       只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示

       为了与 Number 类型区别,BigInt 类型的数据必须添加后缀n

       不能与普通数值进行混合运算

5. 函数的扩展

  • 允许为函数的参数设置默认值
function Point(x = 0, y = 0) {
  this.x = x;
  this.y = y;
}

const p = new Point();
p // { x: 0, y: 0 }
  • length属性   返回没有指定默认值的参数个数
  • 作用域   一旦设置了参数默认值, 函数进行声明初始化时, 参数会形成单独的作用域
  • rest参数  形式为(...变量名),  获取函数的多余参数
  • 箭头函数

       基本用法 : 

var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

var f = v => v;

// 等同于
var f = function (v) {
  return v;
};

        注意 : 

              函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

              不可以使用new命令

              不可以使用arguments对象

              不可以使用yield命令

         不适用场合 : 

              定义对象的方法,且该方法内部包括this

     需要动态this的时候,也不应使用箭头函数

  • 尾调用优化(只在严格模式下开启)

       指某个函数的最后一步是调用另一个函数

function f(x){
  return g(x);
}

       以下三种情况, 不属于尾调用

// 情况一
function f(x){
  let y = g(x);
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;
}

// 情况三
function f(x){
  g(x);
}

       作用 : 大大节省内存

       注意 : 目前只有 Safari 浏览器支持尾调用优化,Chrome 和 Firefox 都不支持

  • 尾递归

        尾调用自身,就称为尾递归, 不会发生栈溢出

  • catch命令的参数省略

6. 数组的扩展

  • 扩展运算符

       三个点... , 将一个数组转为用逗号分隔的参数序列

       只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错

       应用 : 

              (1)复制数组

const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
//a2都是a1的克隆

              (2)合并数组

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

               (3)与解构赋值结合

                    用于数组赋值时, 只能放在参数的最后一位

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

                 (4)字符串

[...'hello']
// [ "h", "e", "l", "l", "o" ]

                 (5)实现了Iterator接口的对象

                     任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组

  • 方法

       Array.from()   将类似数组的对象和可遍历的对象转为真正的数组

       Array.of()  将一组值, 转换为数组

  • 实例方法

       copyWithin()  在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组

       find()  返回第一个符合条件的数组成员, 参数为回调函数, 没有则返回undefined

       findIndex()  返回第一个符合条件的数组位置, 没有则返回-1

       fill() 使用给定值, 填充数组, 参数2填充起始位置, 参数3结束位置

       keys() 遍历键名

       values()  遍历键值

       entries()  遍历键值对

       includes()  是否包含指定值

       flat()  将嵌套数组变为一维数组

       flatMap() 对数组每个成员执行一个函数

7. 对象的扩展

  • 简介表示法
let birth = '2000/01/01';

const Person = {

  name: '张三',

  //等同于birth: birth
  birth,

  // 等同于hello: function ()...
  hello() { console.log('我的名字是', this.name); }

};
  • 属性名表达式
let lastWord = 'last word';

const a = {
  'first word': 'hello',
  [lastWord]: 'world'
};

a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
  • 属性的可枚举性

       属性中的描述对象getOwnPropertyDescriptor中enumerable属性, 如果为false, 表示某些操作会忽略当前属性

       以下操作会忽略enumerable为false属性

              for...in循环    只遍历对象自身的和继承的可枚举的属性

              Object.keys()   返回对象自身的所有可枚举的属性的键名

              JSON.stringify()  只串行化对象自身的可枚举的属性

              Object.assign()  只拷贝对象自身的可枚举的属性

  • 属性的遍历

        for...in   循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)

        Object.keys   返回对象自身的所有可枚举的属性的键名(不含 Symbol 属性)

        Object.getOwnPropertyNames  返回对象自身的所有属性的键名(不含 Symbol 属性)

        Object.getOwnPropertySymbols  返回对象自身的所有 Symbol 属性的键名

        Reflect.ownKeys   包含对象自身的所有键名

  • super关键字

        指向当前对象的原型对象

        只能用在对象的方法之中

  • 扩展运算符...

       解构赋值

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

        取出参数对象的所有可遍历属性

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
  • 链判断运算符?.

       判断对象是否存在, 存在则取出某个属性值

const firstName = message?.body?.user?.firstName || 'default';

a?.b
// 等同于
a == null ? undefined : a.b

a?.[x]
// 等同于
a == null ? undefined : a[x]

a?.b()
// 等同于
a == null ? undefined : a.b()

a?.()
// 等同于
a == null ? undefined : a()

        注意 : 

              短路机制   不满足条件, 就不再往下执行

              delete运算符   如果为undefined或null, 会直接返回undefined, 不会进行delete运算

              括号的影响   只对括号内部有影响

              报错场合   构造函数 / 右侧有模板字符串 / 左侧是super / 用于赋值运算符左侧

              右侧不得为十进制数值

  • Null判断运算符??

        只有运算符左侧的值为nullundefined时,才会返回右侧的值

const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;
  • 方法

       Object.is()  比较两个值是否严格相等, 与===的不同, +0不等于-0; NaN等于自身

       Object.assign()  对象的合并, 将源对象的所有可枚举属性, 复制到目标的对象

                   常见用途 : 添加属性 / 添加方法 / 克隆对象 / 合并多个对象 / 为属性指定默认值

                   注意 : 浅拷贝 / 同名属性的替换 / 数组的处理 / 取值函数求值后再赋值

       Object.setPrototypeOf()  设置一个对象的原型对象

       Object.keys()  返回对象自身的所有可遍历属性键名

       Object.values()  返回对象自身的所有可遍历属性的键值

       Object.entries()  返回对象自身的所有可遍历属性的键值对数组

       Object.fromEntries()  将一个键值对数组转为对象

8 . Symbol

       表示独一无二的值

  • Symbol.prototype.description   Symbol的描述, 创建时可添加
  • 作为属性名的Symbol    不能使用点运算符
  • 属性名的遍历

       Object.getOwnPropertySymbols()   返回对象自身的所有 Symbol 属性的键名

       Reflect.ownKeys()  返回所有类型的键名,包括常规键名和 Symbol 键名

  • Symbol.for  搜索有没有以该参数作为名称的 Symbol 值。有就返回这个 Symbol 值,否则就新建, 并将其注册到全局
  • Symbol.keyFor()  返回一个已登记的 Symbol 类型值的key

9. Set和Map

  • Set

       类似数组, 成员的值都是唯一的

       实例属性/方法 : 

              size   成员总数

              add()  添加值

              delete() 删除值

              has() 是否为Set成员

              clear()  清除所有成员

              keys() / values() / entries()  返回键值/ 键值对遍历器

              forEach()  使用回调函数遍历每个成员

  • Map

       键值对集合

       实例属性/方法 : 

              size  成员总数

              set()  设置键名对应键值

              get()  读取键名对应的值, 找不到key, 返回undefined

              has()  某键是否在当前Map对象中

              delete() 删除某个键

              clear()  清除所有成员

              keys() / values() / entries()  返回键名/键值/ 键值对遍历器

              forEach()  遍历Map的所有成员

        互相转换 : 

              (1)Map转为数组

const map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

[...map.keys()]
// [1, 2, 3]

[...map.values()]
// ['one', 'two', 'three']

[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]

[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]

               (2)数组转为Map

new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])

                (3)Map转为对象

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }

                (4)对象转Map

let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));

10. Proxy

         在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截

11. Reflect

         目的 : 

                (1) 将Object对象的一些明显属于语言内部的方法, 放到Reflect对象上

                (2) 修改某些Object方法的返回结果,让其变得更合理

                (3) 让Object操作都变成函数行为

                (4) Reflect对象的方法与Proxy对象的方法一一对应

12. Generator 函数

         ES6提供的一种异步编程解决方案

         语法上可以理解为状态机, 封装了多个内部状态

         特征 : 

                function 关键字与函数名之间有一个星号

                函数体内部使用yield表达式, 定义不同的内部状态

                分段执行, yield表达式是暂停执行标记, next方法恢复执行

         使用 : 

                调用后, 并不执行, 指向内部状态的指针对象

                下一步, 调用遍历器对象的next方法, 使得指针移向下一个状态

                每次调用next方法, 内部指针就从函数头部或上一次停下来的地方开始执行

                直到遇到下一个yield表达式或return语句为止

13. async 函数

         Generator 函数的语法糖

         将 Generator 函数的星号(*)替换成async,将yield替换成await

         对 Generator 函数的改进 :

              (1)内置执行器

                  与普通函数一样执行, 无需调用next方法, 或用co模块

              (2)更好的语义

                  asyncawait,比起星号和yield,语义更清楚了

                  async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果

              (3)更广的适用性

              (4)返回值是 Promise

                   await命令就是内部then命令的语法糖

          await命令后是一个Promise 对象, 返回该对象的结果, 否则, 直接返回对应的值

          注意 : 

                  await命令放在try...catch中

                  不存在继发关系, 最好同时触发

                  await命令只能用在async函数中

                  async函数可以保留运行堆栈

14. Class

          引入Class类概念, 作为对象的模板

          类的数据类型就是函数, 类本身指向构造函数

          类的所有方法都定义在类的prototype属性上面

          类必须使用new调用

          类必须有constructor()方法, 没有显式定义, 会默认添加空的constructor()方法

          实例的属性除非显式的定义在其本身(this对象上), 否则都是定义在原型上

          static修饰静态方法,属性

          前缀#修饰私有方法, 属性

          new.target属性, 返回new命令作用于的构造函数

          通过extends关键字实现继承

          Object.getPrototypeOf() 从子类上获取父类

          super作为函数调用时, 代表父类的构造函数

          super作为对象时, 在普通方法中, 指向父类的原型对象; 静态方法中, 指向父类

15. Module 语法

         ES6 的模块自动采用严格模式

         一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取

         可以出现在模块的任何位置, 处于模块顶层就可以, 处于块级作用域内, 会报错

         可以用as关键字重命名

         export 命令 : 

              用于规定模块的对外接口

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export { firstName, lastName, year };

         import 命令 : 

               用于输入其他模块提供的功能              

import { lastName as surname } from './profile.js';

         模块的整体加载

import * as circle from './circle';

console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));

          export default 命令 : 

                 为模块指定默认输出

                 一个模块只能有一个默认输出

                 其他模块加载该模块时, import命令可以指定任意名字, 不使用大括号

          复合写法 : 

                 相当于对外转发, 当前模块无法直接使用

export { foo, bar } from 'my_module';

// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };

           import() : 

               动态加载指定的模块, 可以用在任何地方

               适用场合 : 

                     (1)按需加载    在需要的时候, 再加载

                     (2)条件加载    根据不同的情况, 加载不同的模块

                     (3)动态的模块路径   允许模块路径动态生成

           浏览器加载 : 

                   通过<script>标签加载 JavaScript 脚本

                   打开deferasync属性,脚本就会异步加载

                   defer 等到页面在内存中正常渲染结束后执行

       async 下载完执行, 无法保证加载顺序

16. 编程风格

  • 块级作用域

       let 取代 var     语义相近, let没有副作用

       let和const之间, 优先使用const

  • 字符串

        静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号

  • 解构赋值

       使用数组成员对变量赋值时, 优先使用解构赋值

const arr = [1, 2, 3, 4];
const [first, second] = arr;

       函数的参数如果是对象的成员,优先使用解构赋值

function getFullName({ firstName, lastName }) {}

       函数返回多个值,优先使用对象的解构赋值

function processInput(input) {
  return { left, right, top, bottom };
}

const { left, right } = processInput(input);
  • 对象

        单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾

const a = { k1: v1, k2: v2 };
const b = {
  k1: v1,
  k2: v2,
};

        对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法

const a = {};
Object.assign(a, { x: 3 });

// good
const a = { x: null };
a.x = 3;

       如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义

const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
};

       对象的属性和方法,尽量采用简洁表达法

const atom = {
  ref,

  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};
  • 数组

        使用扩展运算符(...)拷贝数组

const itemsCopy = [...items];

         使用 Array.from 方法,将类似数组的对象转为数组

  • 函数

        立即执行函数可以写成箭头函数的形式

(() => {
  console.log('Welcome to the Internet.');
})();

         匿名函数当作参数的场合,尽量用箭头函数代替

// good
[1, 2, 3].map((x) => {
  return x * x;
});

// best
[1, 2, 3].map(x => x * x);

          不要在函数体内使用 arguments 变量,使用 rest 运算符(...)代替

function concatenateAll(...args) {
  return args.join('');
}

          使用默认值语法设置函数参数的默认值

function handleThings(opts = {}) {}
  • Class

       用 Class,取代需要 prototype 的操作

       使用extends实现继承

  • 模块

       使用import取代require

       如果模块只有一个输出值,就使用export default

       如果模块有多个输出值,就不使用export default

       export default与普通的export不要同时使用

       不要在模块输入中使用通配符。因为这样可以确保你的模块之中,有一个默认输出(export default)

       如果模块默认输出一个函数,函数名的首字母应该小写

       如果模块默认输出一个对象,对象名的首字母应该大写

  • ESLint

       语法规则和代码风格的检查工具

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值