hawx1993 / tech-blog

📦My personal tech blog,not regularly update
http://sf.gg/u/trigkit4/articles
339 stars 30 forks source link

你不知道的ECMAScript6 #9

Open hawx1993 opened 7 years ago

hawx1993 commented 7 years ago

编译时加载

ES6模块不是对象,而是通过export命令显式指定输出的代码,输入时也采用静态命令的形式。


// ES6模块

import { stat, exists, readFile } from 'fs';

上面代码的实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”,即ES6可以在编译时就完成模块加载,效率要比CommonJS模块的加载方式高。当然,这也导致了没法引用ES6模块本身,因为它不是对象。

函数

默认参数

可以直接在默认参数中调用函数,但当函数提供实参时,默认参数并不会直接调用函数,而是使用实参:

function addValue(a,b){
    return a+b;
}
function add(a,b=addValue(1,2)){
    return a+b;
}
console.log(add(1,2));//3
console.log(add(1));//4

function foo(x = 3) {
    console.log( x );
}
foo();                    // 3
foo( undefined );        // 3
foo( null );            // null
foo( 0 );                // 0

ES6函数参数变量是默认声明的,所以不能用let或const再次声明。默认参数只有当传入的值是undefined时,才会生效

剩余参数rest和扩展运算符

一个函数只能有一个剩余参数,且必须放在最后面。设计剩余参数的目的是用来替代 ECMAScript 中的 arguments。

扩展运算符好比rest的逆运算,用于将数组转为用逗号分隔的参数序列,而剩余参数允许你把多个独立的参数整合到一个数组中。 rest参数的形式为:...变量名;扩展运算符是三个点(...

比如,在使用Math.max计算一个数组中最大的数:

let value = [1,10,100,-1000];
Math.max.apply(null,value);//100

//使用扩展运算符
console.log(Math.max(...value));//100

args 无论是不是空的,它永远是一个数组。但它不包含已经命名的 x,y 和 z 参数,只会包含超出前三个值的传入参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中:

function foo(x,y,z,...args) {
    console.log( x, y, z, args );
}

foo();                    // undefined undefined undefined []
foo( 1, 2, 3 );            // 1 2 3 []
foo( 1, 2, 3, 4 );        // 1 2 3 [ 4 ]
foo( 1, 2, 3, 4, 5 );    // 1 2 3 [ 4, 5 ]

function bar(...args) {
    console.log( args[3] );//4
    console.log(args);//[1, 2, 3, 4, 5]
}

var arr = [ 1, 2, 3, 4, 5 ];
bar( ...arr ); 
bar( arr );// args =>  [[1,2,3,4,5]]; ...args => [1,2,3,4,5]

在形参列表,它把实参整合。在实参列表,它把实参展开。

扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。扩展运算符用于对象中,等同于Object.assign()

let obj = {name: 'trigkit4', age: 23}; 
console.log({...obj});// {name: 'trigkit4', age: 23}

rest参数和arguments对象的区别

-rest参数只包含那些没有对应形参的实参;而 arguments 对象包含了传给函数的所有实参。

解构赋值

解构也可以设置默认值:

const getUserName = () => {
  return {
         name1: 'mike',
         name2: 'jake'
    };
};
const {name1, name3 = 'trigkit4'} = getUserName();
name3;//trigkit4
//结构数组可跳过其中某几项
const browserSet = ['chrome','safari','firefox','edge'];
const [b1,b2,,b3] = browserSet;
b1;//chrome
b3;//edge

//设置默认值
function getAges(
    {age1=10,age2=20} = {}
){
    console.log(age1,age2)
}
getAges({});//10 20

function getAge(
    {age1,age2} = {age1:1,age2:2}
){
    console.log(age1,age2)
}
getAge();//1,2
getAge({});//undefined undefined
getAge({age1:3});//3 undefined

new Set与数组去重

Set 内无重复的值

const arr = [...new Set([1, 2, 3, 3, NaN, NaN])]
// [1, 2, 3, NaN]  

对象字面量

const name = 'Jane';
const age = 20

const person = {
  [name]: true,
  [age]: true
}
//Object {20: true, Jane: true}

箭头函数

箭头函数不属于普通的 function,所以没有独立的上下文。箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域(如果没有就是全局)。如果你在箭头函数中使用了this,那么该this一定就是外层的this。箭头函数会继承当前上下文的 this 关键字。


const person = {
    name: 'trigkit4',
    getName: () => this.name
}

// 编译结果却是
'use strict';

var person = {
    name: 'trigkit4',
    getName: function getName() {
        return undefined.name;
    }
};

该箭头函数的外层作用域是window对象,在ES6中,会默认采用严格模式,因此this也不会自动指向window对象了,而箭头函数本身并没有this,因此this就只能是undefined

在以下场景中不要使用箭头函数去定义:

-定义对象方法、定义原型方法、定义构造函数、定义事件回调函数。

箭头函数没有arguments对象,但可以使用rest参数:

let fn = (a,b) =>{
    console.log(arguments)
}
fn(1,2);//arguments is not defined

let fn = (...args) =>{
    console.log(...args)
}
fn(1,2);//1 2

箭头函数会继承当前上下文的 this 关键字

//例如:
    [1,2,3].map( x => x + 1 )

//等同于:
    [1,2,3].map((function(x){
        return x + 1
    }).bind(this))

import 和require

import 不能和 module.exports 一起用,能用的话就可以修改 export 的内容了。

let和const

let不会向window分配任何内容:

let me = "go";  // 全局作用域
console.log(window.me); //undefined

const

const是只读变量。const 对象仍然可以被改变的。

const abc = {a: 'a'};
abc.a = 'b';
console.log(abc);//Object {a: "b"}

Promise

如果一个 promise 失败,all和race也将 reject(拒绝)。

var p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("1"), 1001)
})
var p2 = new Promise((resolve, reject) => {
  setTimeout(() => reject("2"), 1)
})

Promise.race([p1, p2]).then((res) => {
   console.log("success" + res)
}, res => {
   console.log("error " + res)
})

Promise.all([p1, p2]).then((res) => {
   console.log("success" + res)
}, res => {
   console.log("error " + res)
})
//error 2
//error 2

Generator 函数

Generator 函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。

var go = function*(){  
    yield 1;  
    yield 2;  
    yield 3;  
  };  
[...go()] // [1, 2, 3] 

for...of循环可以使用的范围包括数组、Set 和 Map 结构、类数组对象(比如arguments对象、DOM NodeList 对象)以及 Generator 对象和字符串