CodeLife

vuePress-theme-reco yuqing521    2019 - 2020
CodeLife CodeLife

Choose mode

  • dark
  • auto
  • light
主页
分类
  • 日常
  • 后端
  • 基础知识
  • 前端
  • 读书
标签
时间轴
文档
  • vuepress-reco
Github
联系我
  • 关于我
  • CSDN
  • 掘金
author-avatar

yuqing521

22

文章

25

标签

主页
分类
  • 日常
  • 后端
  • 基础知识
  • 前端
  • 读书
标签
时间轴
文档
  • vuepress-reco
Github
联系我
  • 关于我
  • CSDN
  • 掘金
  • 重学 ES6

    • 块级作用域变量
      • 模板字符串代替字符串拼接
        • padStart()、padEnd()
          • 解构赋值
            • 加强循环
              • 散布运算符 与 rest 参数
                • 散布运算符
                • rest 参数
              • includes()方法
                • import & export 方法
                  • 命名导出
                  • 默认导出
                  • 类 Class
                • promise & async & await
                  • Promise
                  • async await
                • Map & Set
                  • Map
                  • Set

              重学 ES6

              vuePress-theme-reco yuqing521    2019 - 2020

              重学 ES6


              yuqing521 2020-12-25 JavaScriptES6

              image.png

              # 重学 ES6

              # 块级作用域变量

              let word1 = 'hello'
              const word2 = 'world'
              
              1
              2

              let 用于声明变量 const 用于声明常量,常量一旦声明便无法更改

              使用 let 和 const 声明的变量是有块级作用域(函数体,判断体,循环体等)

              因此建议使用 es6 语法中 let const 来定义变量

              # 模板字符串代替字符串拼接

              const a = 'hello'
              const b = 'world'
              
              // in ES5
              const c = a + ' ' + b 
              
              // in ES6 used 模板字符串
              const d = `${a} ${b}`
              
              1
              2
              3
              4
              5
              6
              7
              8

              # padStart()、padEnd()

              新的字串填充方法,可以从start位置或是end位置,开始填充到指定数字长度,被填充的内容为第二个参数。

              let astring = 'moment'
              console.log(astring.padStart(10,'m'))
              // 'mmmmmoment'
              
              console.log('abc'.padStart(10, "foo"))
              // "foofoofabc"
              
              console.log('abc'.padEnd(10, "foo"))
              // 'abcfoofoof'
              
              1
              2
              3
              4
              5
              6
              7
              8
              9

              # 解构赋值

              // in ES5
              let firstName = personalInformation.firstName
              let lastName = personalInformation.lastName
              let city = personalInformation.city
              
              // in ES6 used 对象解构赋值
              let { firstName: fn, lastName: ln, city: ct } = personalInformation
              
              1
              2
              3
              4
              5
              6
              7

              从 personalInformation 对象中读取 firstName , lastName , city 几个属性,并用 fn , ln , ct 几个别名作为解构赋值后新变量的名字,如果未声明别名,默认使用 firstName , lastName , city 作为解构后的变量名

              // in ES6 used 数组解构赋值
              let [firstName, lastName, city] = ['Dylan', 'Israel', 'Austin']
              
              1
              2

              使用数组解构赋值时默认为按照数组顺序,逐一读取

              # 加强循环

              最早的数组遍历方式

              var a = ["a", "b", "c"];
              for(var index = 0;index < a.length;index++){
                console.log(a[index]);
              }
              
              1
              2
              3
              4

              自从ES5发布以后,可以用内建的forEach来遍历数组

              var a = ["a", "b", "c"];
              a.forEach(function(element) {
                  console.log(element);
              });
              
              1
              2
              3
              4

              推荐在循环普通对象属性的时候,使用 for...in 在遍历数组的时候的时候使用 for...of

              for...in循环出的是key ,for...of循环出的是value

              for...of 不能循环普通的对象 需要通过和 Object.keys() 搭配使用

              # 散布运算符 与 rest 参数

              # 散布运算符

              const t = [1, 2, 3, 4, 5]
              
              const [first, second, ...rest] = t
              
              console.log(first, second)  // 1, 2 is printed
              console.log(rest)          // [3, 4 ,5] is printed
              
              1
              2
              3
              4
              5
              6

              上面语法中的三个点 (...) 是散布运算符,其目标选定是特定变量中的整个值。

              # rest 参数

              实际使用中经常遇到可变参数的情况,以定义函数实现计算传入所有参数的和为例.

              使用arguments参数

              **function** sumArgu () {
                   **var** result **=** 0;
                   **for** (**var** i **=** 0; i **<** arguments.length; i**++**) {
                      result **+=** arguments[i];
                  }
                  **return** result
              }
              console.log(sumArgu(1,2,3));*//6*
              
              1
              2
              3
              4
              5
              6
              7
              8

              使用rest参数

              **function** sumRest (...m) {
              	**var** total **=** 0; 
              	**for**(**var** i **of** m){
              	    total **+=** i;
              	}
              	**return** total;
              }
              console.log(sumRest(1,2,3));*//6*
              
              1
              2
              3
              4
              5
              6
              7
              8

              上述两种方法看似差不多,但是操作的元素有本质的区别,其中arguments是一个类数组,本质是对象;而rest参数m,是真正的数组,可以正常调用数组的所有方法.所以在某些场景中,无需将arguments转为真正的数组,可以直接使用rest参数代替

              # includes()方法

              Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。

              [1, 2, 3].includes(3, 3); // false
               
              [1, 2, 3].includes(3, -1); // true
              
              1
              2
              3

              第一个参数是要查找的元素

              第二个参数表示搜索的起始位置,默认为 0 。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为 -4 ,但数组长度为 3 ),则会重置为从 0 开始。

              [NaN].indexOf(NaN)
              
              // -1
              
              includes使用的是不一样的判断算法,就没有这个问题。
              
              [NaN].includes(NaN)
              
              // true
              
              1
              2
              3
              4
              5
              6
              7
              8
              9

              对比indexof方法

              indexOf方法有两个缺点

              一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于 -1 ,表达起来不够直观。

              二是,它内部使用严格相当运算符( === )进行判断,这会导致对NaN的误判。

              # import & export 方法

              ES6中export和import一般的用法有两种

              1. 命名导出(Named exports)
              2. 默认导出(Default exports)
              // 导出单个特性
              export let name1, name2, …, nameN; // also var, const
              export let name1 = …, name2 = …, …, nameN; // also var, const
              export function FunctionName(){...}
              export class ClassName {...}
              
              // 导出列表
              export { name1, name2, …, nameN };
              
              // 重命名导出
              export { variable1 as name1, variable2 as name2, …, nameN };
              
              // 解构导出并重命名
              export const { name1, name2: bar } = o;
              
              // 默认导出
              export default expression;
              export default function (…) { … } // also class, function*
              export default function name1(…) { … } // also class, function*
              export { name1 as default, … };
              
              // 导出模块合集
              export * from …; // does not set the default export
              export * as name1 from …; // Draft ECMAScript® 2O21
              export { name1, name2, …, nameN } from …;
              export { import1 as name1, import2 as name2, …, nameN } from …;
              export { default } from …;
              
              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22
              23
              24
              25
              26
              27

              # 命名导出

              //------ lib.js ------
              const sqrt = Math.sqrt;
              function square(x) {
                  return x * x;
              }
              function diag(x, y) {
                  return sqrt(square(x) + square(y));
              }
              export {sqrt, square, diag}
              
              // 把export直接加到声明前面就可以省略{}
              export function square(x) {
                  return x * x;
              }
              export function diag(x, y) {
                  return sqrt(square(x) + square(y));
              }
              
              //------ main.js ------
              import { square, diag } from 'lib';				
              console.log(square(11)); // 121
              console.log(diag(4, 3)); // 5
              
              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22

              无论怎样导出,引入的时候都需要{}

              // 别名导入
              import {speak as cowSpeak} from './cow.js'
              import {speak as goatSpeak} from './goat.js'
              
              1
              2
              3

              别名导入使用 变量名 as 别名 导入对象

              当从每个模块需要引入的方法很多的时候,这种写法就显得十分的繁琐、冗长,因此使用命名空间引入

              import * as cow from './cow.js'
              import * as goat from './goat.js'
              
              cow.speak() // moo
              goat.speak() // baa
              
              1
              2
              3
              4
              5

              # 默认导出

              默认导出就不需要name了,但是一个js文件中只能有一个export default 但也可以导出多个方法。

              export default {
                speak () {
                  return 'moo'
                },
                eat () {
                  return 'cow eats'
                },
                drink () {
                  return 'cow drinks'
                }
              }
              
              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11

              引入与命名空间引入类似

              import cow from './default-cow.js'
              import goat from './default-goat.js'
              
              cow.speak() // moo
              goat.speak() // baa
              
              1
              2
              3
              4
              5

              # 类 Class

              // 在ES6中,我们终于有新的语法糖可以使用class了
              class Animal{
                constructor(name,color){
                  this.name = name
                  this.color = color
                }
                toString(){
                  console.log('name:'+this.name+',color:'+this.color)
                }
              }
              const animal = new Animal('dog','white')
              console.log(animal.toString()) // "name:dog,color:white"
              
              // 以下为继承
              class Cat extends Animal{
                constructor(action){
                  // 记得这边要先super,才可以拿到父的资料
                  super('cat','white')
                  this.action = action
                }
                toString(){
                  console.log(super.toString())
                }
              }
              const CCat = new Cat('Catch')
              console.log(CCat.toString()) // "name:cat,color:white"
              
              console.log(CCat instanceof Cat) // true
              
              console.log(CCat instanceof Animal) // true
              
              1
              2
              3
              4
              5
              6
              7
              8
              9
              10
              11
              12
              13
              14
              15
              16
              17
              18
              19
              20
              21
              22
              23
              24
              25
              26
              27
              28
              29
              30

              ES6 提供了 类似于面向对象的声明方法(实现封装继承,提供构造器)

              # promise & async & await

              # Promise

              Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。

              本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。

              # async await

              在ES6为了要解决回调的问题,出现了Promise的then函数,但当逻辑很多时,,要链式多个then函数,会造成语意不清楚

              new Promise((resolve,reject) => { resolve(42)}
              .then(() => { do one})
              .then(() => { do two})
              .catch(() => {console.log(err)})
              )
              
              1
              2
              3
              4
              5

              在ES8中,把非同步做得更方便,而这其实就是Promise与Generator的组合,而变成语法糖。

              async function xxx(){
                  await do One
                  await do_Two
              }
              
              1
              2
              3
              4

              # Map & Set

              JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。

              为了解决这个问题,最新的ES6规范引入了新的数据类型Map

              # Map

              Map是一组键值对的结构,具有极快的查找速度。

              var names = ['Michael', 'Bob', 'Tracy'];
              var scores = [95, 75, 85];
              var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
              m.get('Michael'); // 95
              
              1
              2
              3
              4

              初始化Map需要一个二维数组,或者直接初始化一个空Map。

              Map具有以下方法:

              var m = new Map(); // 空Map
              m.set('Adam', 67); // 添加新的key-value
              m.set('Bob', 59);
              m.has('Adam'); // 是否存在key 'Adam': true
              m.get('Adam'); // 67
              m.delete('Adam'); // 删除key 'Adam'
              m.get('Adam'); // undefined
              
              1
              2
              3
              4
              5
              6
              7

              由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:

              var m = new Map();
              m.set('Adam', 67);
              m.set('Adam', 88);
              m.get('Adam'); // 88
              
              1
              2
              3
              4

              # Set

              Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。

              要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:

              var s1 = new Set(); // 空Setvar s2 = new Set([1, 2, 3]); // 含1, 2, 3
              
              1

              重复元素在Set中自动被过滤:

              var s = new Set([1, 2, 3, 3, '3']);
              s; // Set {1, 2, 3, "3"}
              
              1
              2

              数组中数字3和字符串'3'是不同的元素。

              Set具有以下方法:

              var s = new Set([1, 2, 3]);
              // add(key)方法可以添加元素到Set中可以重复添加,但不会有效果:
              s.add(4);
              s; // Set {1, 2, 3, 4}
              s.add(4);
              s; // Set {1, 2, 3, 4}
              //delete(key)方法可以删除元素:
              s.delete(3);
              s;// Set{1, 2, 4}
              
              1
              2
              3
              4
              5
              6
              7
              8
              9