es6杂记

let 和 const

let

  1. 仅在代码块里有效

    {
    let a = 10;
    var b = 1;
    } a // ReferenceError: a is not defined.
    b // 1
  2. for循环比价适合用let

    你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

  3. 不存在变量提升

  4. 暂时性死区 temporal dead zone TDZ

    var tmp = 123;
    if (true) {
    tmp = 'abc'; // ReferenceError
    let tmp;
    }

    ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

    typeof如果跟了let在后面,会报错,如果没有let,只会是undefined

    隐蔽TDZ

    function bar(x = y, y = 2) {
    return [x, y];
    } bar(); // 报错

    上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。如果y的默认值是x,就不会报错,因为此时x已经声明了。

    function bar(x = 2, y = x) {
    return [x, y];
    }
    bar(); // [2, 2]

    另外,下面的代码也会报错,与var的行为不同。

    // 不报错
    var x = x; // 报错
    let x = x;
    // ReferenceError: x is not defined
  5. let不允许在相同作用域内,重复声明同一个变量。

    function func(arg) {
    let arg; // 报错
    } function func(arg) {
    {
    let arg; // 不报错
    }
    } // 报错
    function func() {
    let a = 10;
    var a = 1;
    } // 报错
    function func() {
    let a = 10;
    let a = 1;
    }

const

  1. const声明一个只读的常量。一旦声明,常量的值就不能改变。(一般大写)

  2. 必须给初值

  3. 与let一样,仅在代码块里有效

  4. 也存在TDZ

  5. 不允许重复声明

  6. 本质

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

    对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

    但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

全局变量与顶层对象脱钩

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1 let b = 1;
window.b // undefined

变量的解构赋值

数组的解构赋值

  1. 基本用法

    let [a, b, c] = [1, 2, 3];

    一些例子

    完全解构
    let [foo, [[bar], baz]] = [1, [[2], 3]];
    foo // 1
    bar // 2
    baz // 3 let [ , , third] = ["foo", "bar", "baz"];
    third // "baz" let [x, , y] = [1, 2, 3];
    x // 1
    y // 3 let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4] let [x, y, ...z] = ['a'];
    x // "a"
    y // undefined
    z // []

    如果解构不成功,变量的值就等于undefined。

    不完全解构
    
    let [x, y] = [1, 2, 3];
    x // 1
    y // 2 let [a, [b], d] = [1, [2, 3], 4];
    a // 1
    b // 2
    d // 4
  2. 默认值

    let [foo = true] = [];
    foo // true let [x, y = 'b'] = ['a']; // x='a', y='b'
    let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

    判断是否===undefined

    let [x = 1] = [undefined];
    x // 1 let [x = 1] = [null];
    x // null

对象的解构赋值

  1. 基本语法

    let { foo, bar } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"

    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let { bar, foo } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb" let { baz } = { foo: "aaa", bar: "bbb" };
    baz // undefined

字符串的解构赋值

  1. 基本语法

    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o" let {length : len} = 'hello';
    len // 5

函数解构赋值

解构赋值的用途

  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. 函数参数的定义

    解构赋值可以方便地将一组参数与变量名对应起来。

  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. 函数参数的默认值

  6. 输入模块的指定方法

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

字符串的扩展

  1. includes(), startsWith(), endsWith()

    includes():返回布尔值,表示是否找到了参数字符串。

    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

    这三个方法都支持第二个参数,表示开始搜索的位置。

    let s = 'Hello world!';
    
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false
  2. repeat()

    'x'.repeat(3) // "xxx"
    'hello'.repeat(2) // "hellohello"
    'na'.repeat(0) // ""

    小数会被取整

  3. 拼接 ,变量用${ }

数值的扩展

  1. Number.isFinite(), Number.isNaN()

    注意:

    Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

  2. Number.parseInt(), Number.parseFloat()

    // ES5的写法
    parseInt('12.34') // 12
    parseFloat('123.45#') // 123.45 // ES6的写法
    Number.parseInt('12.34') // 12
    Number.parseFloat('123.45#') // 123.45
  3. Number.isInteger()用来判断一个数值是否为整数。

    Number.isInteger(25) // true
    Number.isInteger(25.0) // true
    Number.isInteger(25.1) // false

    如果参数不是数值,Number.isInteger返回false。

    Number.isInteger('15') // false

    如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger可能会误判。

对象的扩展

  1. 默认值

    function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;
    } const p = new Point();
    p // { x: 0, y: 0 }
  2. rest

  3. 箭头函数

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

    箭头函数有几个使用注意点。

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

    (2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

    (3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

    (4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

数组的扩展

  1. Array.from(),会返回一个新数组

    let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
    }; // ES5的写法
    var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法
    let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

    Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

    Array.from(arrayLike, x => x * x);
    // 等同于
    Array.from(arrayLike).map(x => x * x); Array.from([1, 2, 3], (x) => x * x)
    // [1, 4, 9]
  2. 数组实例的 includes()

    [1, 2, 3].includes(2)     // true
    [1, 2, 3].includes(4) // false
    [1, 2, NaN].includes(NaN) // true
  3. 使用 for of 来遍历数组中的值

    for (let index of ['a', 'b'].keys()) {
    console.log(index);
    }
    // 0
    // 1 for (let elem of ['a', 'b'].values()) {
    console.log(elem);
    }
    // 'a'
    // 'b' for (let [index, elem] of ['a', 'b'].entries()) {
    console.log(index, elem);
    }
    // 0 "a"
    // 1 "b"

    可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

对象的扩展

  1. 属性的简洁表示法

    const foo = 'bar';
    const baz = {foo};
    baz // {foo: "bar"} // 等同于
    const baz = {foo: foo}; const o = {
    method() {
    return "Hello!";
    }
    }; // 等同于 const o = {
    method: function() {
    return "Hello!";
    }
    };

Set 和 Map

Set

  1. ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

    const s = new Set();

    [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

    for (let i of s) {

    console.log(i);

    }

    // 2 3 5 4

    Set和Array的对比:

    1、Set不允许有重复值,但是Array可以
    
    2、Set计算里面的个数,是调用它的size方法,Array用的是length
    
    3、实例方法有 add、delete、has、clear
  2. 遍历

    let set = new Set(['red', 'green', 'blue']);
    
    for (let item of set.keys()) {
    console.log(item);
    }
    // red
    // green
    // blue for (let item of set.values()) {
    console.log(item);
    }
    // red
    // green
    // blue for (let item of set.entries()) {
    console.log(item);
    }
    // ["red", "red"]
    // ["green", "green"]
    // ["blue", "blue"]

    Set 结构的键名就是键值(两者是同一个值)

    可以省略values方法,直接用for...of循环遍历 Set。

    let set = new Set(['red', 'green', 'blue']);
    
    for (let x of set) {
    console.log(x);
    }
    // red
    // green
    // blue

    也可以用foreach

    set = new Set([1, 4, 9]);
    set.forEach((value, key) => console.log(key + ' : ' + value))
    // 1 : 1
    // 4 : 4
    // 9 : 9

    用途

    1. 扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。

      let arr = [3, 5, 2, 2, 5, 5];
      let unique = [...new Set(arr)];
      // [3, 5, 2]
    2. 数组的map和filter方法也可以间接用于 Set 了

      let set = new Set([1, 2, 3]);
      set = new Set([...set].map(x => x * 2));
      // 返回Set结构:{2, 4, 6} let set = new Set([1, 2, 3, 4, 5]);
      set = new Set([...set].filter(x => (x % 2) == 0));
      // 返回Set结构:{2, 4}
    3. 结合filter筛选

      let a = new Set([1, 2, 3]);
      let b = new Set([4, 3, 2]); // 并集
      let union = new Set([...a, ...b]);
      // Set {1, 2, 3, 4} // 交集
      let intersect = new Set([...a].filter(x => b.has(x)));
      // set {2, 3} // 差集
      let difference = new Set([...a].filter(x => !b.has(x)));
      // Set {1}
    4. 将set结构的数据变成数组

      // 方法一
      let set = new Set([1, 2, 3]);
      set = new Set([...set].map(val => val * 2));
      // set的值是2, 4, 6 // 方法二
      let set = new Set([1, 2, 3]);
      set = new Set(Array.from(set, val => val * 2));
      // set的值是2, 4, 6

Map

它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

注意,0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。

Map 和 对象的比较:

1、对象的key必须是字符串,但是Map的key可以是任何类型
2、map实例方法有 set、get、delete、has、clear
  1. 基本语法

    const m = new Map();
    const o = {p: 'Hello World'}; m.set(o, 'content')
    m.get(o) // "content" m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
  2. 可以接受一个数组

    const map = new Map([
    ['name', '张三'],
    ['title', 'Author']
    ]); map.size // 2
    map.has('name') // true
    map.get('name') // "张三"
    map.has('title') // true
    map.get('title') // "Author"
  3. 遍历

    遍历的顺序就是插入的顺序

    const map = new Map([
    ['F', 'no'],
    ['T', 'yes'],
    ]); for (let key of map.keys()) {
    console.log(key);
    }
    // "F"
    // "T" for (let value of map.values()) {
    console.log(value);
    }
    // "no"
    // "yes" for (let item of map.entries()) {
    console.log(item[0], item[1]);
    }
    // "F" "no"
    // "T" "yes" // 或者
    for (let [key, value] of map.entries()) {
    console.log(key, value);
    }
    // "F" "no"
    // "T" "yes" // 等同于使用map.entries()
    for (let [key, value] of map) {
    console.log(key, value);
    }
    // "F" "no"
    // "T" "yes"
  4. 快速转成数组

    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']]

Promise

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

  1. 基本用法

    Promise对象是一个构造函数,用来生成Promise实例。

    const promise = new Promise(function(resolve, reject) {
    // ... some code if (/* 异步操作成功 */){
    resolve(value);
    } else {
    reject(error);
    }
    });

    Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

    resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

    reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

    promise.then(function(value) {
    // success
    }, function(error) {
    // failure
    });

    then方法可以接受两个回调函数作为参数。

    第一个回调函数是Promise对象的状态变为resolved时调用

    第二个回调函数是Promise对象的状态变为rejected时调用。

    二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

    简单的例子:

    function timeout(ms) {
    return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
    });
    } timeout(100).then((value) => {
    console.log(value);
    });
  2. promise.prototype

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});

    如果该对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

       //使用promise封装耗时的操作
function promiseTimeOut(time,str){
return new Promise((yes,no)=>{
setTimeout(() => {
yes(str)
}, time);
})
} promiseTimeOut(2000,"..第一层..").then(data1=>{
console.log(data1) return promiseTimeOut(2000,'..第二层..')
}).then(data2=>{
console.log(data2) return promiseTimeOut(2000,'..第三层..')
}).then(data3=>{
console.log(data3) return promiseTimeOut(2000,'..第四层..')
}).then(data4=>{
console.log(data4)
})

async 函数

作用:

1.	能解决Promise获取值时then过多的问题
2. 通过同步的方式去调用异步的代码
3. 使得异步操作变得更加方便。

语法:

async 函数名称(){
await 异步操作 await 异步操作
}
     //使用promise封装耗时的操作
function promiseTimeOut(time,str){
var promise = new Promise((yes,no)=>{
setTimeout(() => {
yes(str)
}, time);
})
return promise
}
function printName(name){
return name
}
async function printStepByStep(){
const result1 = await promiseTimeOut(2000,'。。。第一层。。。')
console.log(result1)
const result2 = await printName("。。。小刘。。。")
console.log(result2)
const result3 = await promiseTimeOut(2000,'。。。第3层。。。')
console.log(result3)
const result4 = await promiseTimeOut(2000,'。。。第四层。。。')
console.log(result4)
}
//调用异步函数
printStepByStep()

注意:

1、我们用async定义的异步函数,必须要调用它,否则不起作用

2、如果await 后面调用的函数,返回的是promise对象,他会自动调用promise的then把结果拿出来,赋值给变量

3、await后面调用的函数里面,除了可以返回promise、也可返回普通的类型

es6杂记的更多相关文章

  1. ES6模块import细节

    写在前面,目前浏览器对ES6的import支持还不是很好,需要用bable转译. ES6引入外部模块分两种情况: 1.导入外部的变量或函数等: import {firstName, lastName, ...

  2. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  3. ES6的一些常用特性

    由于公司的前端业务全部基于ES6开发,于是给自己开个小灶补补ES6的一些常用特性.原来打算花两天学习ES6的,结果花了3天才勉强过了一遍阮老师的ES6标准入门(水好深,ES6没学好ES7又来了...) ...

  4. ES6(块级作用域)

    我们都知道在javascript里是没有块级作用域的,而ES6添加了块级作用域,块级作用域能带来什么好处呢?为什么会添加这个功能呢?那就得了解ES5没有块级作用域时出现了哪些问题. ES5在没有块级作 ...

  5. es6小白学习笔记(一)

    1.let和const命令 1.es6新增了let和const命令,与var用法类似,但它声明的变量只在let所在的代码块内有效(块级作用域,es5只有全局和函数作用域) { let a = 1; v ...

  6. ES6之变量常量字符串数值

    ECMAScript 6 是 JavaScript 语言的最新一代标准,当前标准已于 2015 年 6 月正式发布,故又称 ECMAScript 2015. ES6对数据类型进行了一些扩展 在js中使 ...

  7. ES6之let命令详解

    let与块级作用域 { var foo='foo'; let bar='bar'; } console.log(foo,'var'); //foo varconsole.log(bar ,'bar') ...

  8. ES6 箭头函数中的 this?你可能想多了(翻译)

    箭头函数=>无疑是ES6中最受关注的一个新特性了,通过它可以简写 function 函数表达式,你也可以在各种提及箭头函数的地方看到这样的观点——“=> 就是一个新的 function”. ...

  9. ES6+ 现在就用系列(二):let 命令

    系列目录 ES6+ 现在就用系列(一):为什么使用ES6+ ES6+ 现在就用系列(二):let 命令 ES6+ 现在就用系列(三):const 命令 ES6+ 现在就用系列(四):箭头函数 => ...

随机推荐

  1. 【10】AngularJS SQL

    AngularJS SQL 使用 PHP 从 MySQL 中获取数据 <div ng-app="myApp" ng-controller="customersCtr ...

  2. [luoguP1474] 货币系统 Money Systems(背包)

    传送门 背包 ——代码 #include <cstdio> #include <iostream> #define LL long long int v, n; LL f[10 ...

  3. linux安装java mysql tomcat 环境

    安装jdk: 1. 查看系统版本 uname -a 2.查看操作系统 cat  /proc/version 3.上传安装文件到指定目录   tar -zxvf jdkxxx. 4.修改配置文件  vi ...

  4. android中listview点击监听器onItemClick四个参数的含义

    public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) X, Y两个listvie ...

  5. 1.4-动态路由协议OSPF④

    多区域的OSPF: 划分多区域的主要目的: 1.减少每个区域中的路由条目,进而减少每个路由器的内存中的路由,及其内存消耗,提高转发效率. 2.因为每一个OSPF区域对应在一个OSPF LSDB,配合在 ...

  6. [Vue-rx] Pass Template Data Through domStreams in Vue.js and RxJS

    domStreams enable you to pass additional data along the stream that can be provided by the template ...

  7. Spring MVC : Java模板引擎 Thymeleaf (二)

    本文原计划直接介绍Thymeleaf的视图解析,但考虑到学习的方便,决定先构建一个spring-mvc. 以下的全部过程仅仅要一个记事本和JDK就够了. 第一步,使用maven构建一个web app. ...

  8. 破解IntelliJ IDEA 2017

    一.下载地址 http://www.jetbrains.com/idea/ 二.下载破解jar包 http://idea.lanyus.com/ 2.1 将下载好的jar包放在IDEA的bin文件下 ...

  9. Meter Bus解析4:升压斩波电路

             Meter Bus解析1(http://blog.csdn.net/qingwufeiyang12346/article/details/47767595),对Meter Bus进行 ...

  10. The bytes/str dichotomy in Python 3

    The bytes/str dichotomy in Python 3 - Eli Bendersky's website https://eli.thegreenplace.net/2012/01/ ...