ECMAScript 6

1、Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行

$ npm install --save-dev gulp-babel

2、最常用的ES6特性

let, const, class, extends, super, arrow functions, template string, destructuring, default, rest arguments

3、新特性简介

let、const

可以把let看成var,只是它定义的变量被限定在了特定范围内才能使用,而离开这个范围则无效。

const则很直观,用来定义常量,即无法被更改值的变量。

//var带来的不合理场景就是用来计数的循环变量泄露为全局变量
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

箭头函数:

我们经常需要给回调函数维护一个词法作用域的上下文 this

function Person(name) {

    this.name = name;

}

Person.prototype.prefixName = function (arr) {

    return arr.map(function (character) {

        return this.name + character; // Cannot read property ‘name‘ of undefined

    });

};

一个常用的解决办法是把 this 存在一个变量中:

function Person(name) {

    this.name = name;

}

Person.prototype.prefixName = function (arr) {

    var that = this; // Store the context of this

    return arr.map(function (character) {

        return that.name + character;

    });

};

我们也可以传递一个合适的 this 上下文:

function Person(name) {

    this.name = name;

}

Person.prototype.prefixName = function (arr) {

    return arr.map(function (character) {

        return this.name + character;

    }, this);

}

我们还可以绑定上下文:

function Person(name) {

    this.name = name;

}

Person.prototype.prefixName = function (arr) {

    return arr.map(function (character) {

        return this.name + character;

    }.bind(this));
};

使用 箭头函数,this 将不会受到影响,并且我们可以重写上面的函数:

function Person(name) {

    this.name = name;

}

Person.prototype.prefixName = function (arr) {

    return arr.map(character => this.name + character);

};

在我们写一个函数的时候,箭头函数更加简洁并且可以很简单地返回一个值

var squares = arr.map(function (x) { return x * x }); // Function Expression

const arr = [1, 2, 3, 4, 5];

const squares = arr.map(x => x * x); // Arrow Function for terser implementation

类Class

在 ES6 之前,我们通过构造函数来创造一个类,并且通过原型来扩展属性:

function Person(name, age, gender) {

    this.name   = name;
    this.age      = age;
    this.gender = gender;
}

Person.prototype.incrementAge = function () {

    return this.age += 1;
};

然后可以这样继承类:

function Personal(name, age, gender, occupation, hobby) {

    Person.call(this, name, age, gender);
    this.occupation = occupation;
    this.hobby = hobby;
}

Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
    Person.prototype.incrementAge.call(this);
    this.age += 20;
    console.log(this.age);
};

在 ES6 中,提供了更多的语法糖,可以直接创造一个类:

class Person {
    constructor(name, age, gender) {
        this.name   = name;
        this.age    = age;
        this.gender = gender;
    }

    incrementAge() {

      this.age += 1;
    }
}

使用 extends 关键字来继承一个类:

class Personal extends Person {

    constructor(name, age, gender, occupation, hobby) {

        super(name, age, gender);
        this.occupation = occupation;
        this.hobby = hobby;
    }

    incrementAge() {

        super.incrementAge();
        this.age += 20;
        console.log(this.age);
    }
}

字符串

.includes( )

var string = ‘food‘;
var substring = ‘foo‘;

console.log(string.indexOf(substring) > -1);

之前我们使用 indexOf() 函数的返回值是否 >-1 来判断字符串是否包含某些字符串,现在我们更简单地使用 .includes() 来返回一个布尔值来判断:

const string = ‘food‘;
const substring = ‘foo‘;

console.log(string.includes(substring)); // true

.repeat()

function repeat(string, count) {
    var strings = [];
    while(strings.length < count) {

        strings.push(string);
    }
    return strings.join(‘‘);
}

在 ES6 中,可以更简便地实现:

// String.repeat(numberOfRepetitions)

‘meow‘.repeat(3); // ‘meowmeowmeow‘

使用 模版字符串 我们就可以不用对某些特殊自负进行转义处理了:

var text = "This string contains \"double quotes\" which are escaped.";

let text = `This string contains "double quotes" which don‘t need to be escaped anymore.`;

模版字符串 还支持插入,可以把变量值和字符串连接起来.

var name = ‘Tiger‘;
var age = 13;

console.log(‘My cat is named ‘ + name + ‘ and is ‘ + age + ‘ years old.‘);

更简单:

const name = ‘Tiger‘;
const age = 13;

console.log(`My cat is named ${name} and is ${age} years old.`);

模版字符串 还支持表达式:

let today = new Date();

let text = `The time and date is ${today.toLocaleString()}`;

结构对象

var luke = { occupation: ‘jedi‘, father: ‘anakin‘ };
var occupation = luke.occupation; // ‘jedi‘
var father = luke.father; // ‘anakin‘

//es6
let luke = { occupation: ‘jedi‘, father: ‘anakin‘ };
let {occupation, father} = luke;

console.log(occupation); // ‘jedi‘
console.log(father); // ‘anakin‘

模块

使用commonJs输出

module.exports = 1;

module.exports = { foo: ‘bar‘ };

module.exports = [‘foo‘, ‘bar‘];

module.exports = function bar () {};

使用es6输出

在 ES6 中我们可以暴露多个值,使用 Exports

export let name = ‘David‘;

export let age  = 25;

或者暴露一个对象列表:

function sumTwo(a, b) {

    return a + b;
}

function sumThree(a, b, c) {

    return a + b + c;
}

export { sumTwo, sumThree };

模块导入:

import {

    sumTwo as addTwoNumbers,

    sumThree as sumThreeNumbers

} from ‘math/addition’;

另外,我们可以导入所有的东西(整体加载):

import * as util from ‘math/addition‘;

最后,我们可以从一个模块中导入一个值的列表:

import * as additionUtil from ‘math/addition‘;

const { sumTwo, sumThree } = additionUtil;

可以像这样导入默认绑定的输出:

import api from ‘math/addition‘;

// Same as: import { default as api } from ‘math/addition’;

虽然最好保持出口的简单,但如果需要的话我们有时可以混合默认的进口和混合进口。当我们这样出口的时候:

// foos.js

export { foo as default, foo1, foo2 };

我们可以这样导入它们:

import foo, { foo1, foo2 } from ‘food’;

当我们用 commonjs 的语法导入一个模块的出口时(比如 React),我们可以这样做:

import React from ‘react‘;

const { Component, PropTypes } = React;

还有更精简的写法:

import React, { Component, PropTypes } from ‘react’;

默认参数:

function addTwoNumbers(x, y) {

    x = x || 0;
    y = y || 0;
    return x + y;
}

ES6 中,函数的参数可以支持设置默认值:

function addTwoNumbers(x=0, y=0) {

    return x + y;
}

rest 参数

在 ES5 中,我们需要这么处理不定参数:

function logArguments() {

    for (var i=0; i < arguments.length; i++) {

        console.log(arguments[i]);
    }
}

使用 rest ,我们就可以处理不确定数目的参数:

function logArguments(...args) {

    for (let arg of args) {

        console.log(arg);
    }
}

命名参数

在 ES5 中是使用配置对象的模式来处理命名参数,jQuery 中的使用:

function initializeCanvas(options) {

    var height = options.height || 600;

    var width  = options.width  || 400;

    var lineStroke = options.lineStroke || ‘black‘;

}

我们可以利用解构的一个函数的形参实现相同的功能

function initializeCanvas(

    { height=600, width=400, lineStroke=‘black‘}) {

        // Use variables height, width, lineStroke here

    }

如果我们想使整个值可选择,我们可以结构将一个空的对象:

function initializeCanvas(

    { height=600, width=400, lineStroke=‘black‘} = {}) {

        // ...

    }

展开操作

在 ES5 中,我们可以 apply Math.max 方法来获得一个数组中的最大值:

Math.max.apply(null, [-1, 100, 9001, -32]); // 9001

在 ES6 中,我们可以通过展开操作把一个数组的值作为参数传递给一个函数

Math.max(...[-1, 100, 9001, -32]); // 9001

我们可以更简洁地使用这个语法来合并数组

let cities = [‘San Francisco‘, ‘Los Angeles‘];

let places = [‘Miami‘, ...cities, ‘Chicago‘]; // [‘Miami‘, ‘San Francisco‘, ‘Los Angeles‘, ‘Chicago‘]

symbols是不可改变并且独一无二的,可以在任意哈希中作一个key,调用 Symbol() 或者 Symbol(description) 可以创造一个独一无二的符号,但是在全局是看不到的。Symbol() 的一个使用情况是给一个类或者命名空间打上补丁,但是可以确定的是你不会去更新它。比如,你想给 React.Component 类添加一个 refreshComponent 方法,但是可以确定的是你不会在之后更新这个方法:

const refreshComponent = Symbol();

React.Component.prototype[refreshComponent] = () => {

    // do something

}

Symbol.for(key)

Symbol.for(key) 同样会创造一个独一无二并且不可改变的 Symbol,但是它可以全局看到,两个相同的调用 Symbol.for(key) 会返回同一个 Symbol 类

Symbol(‘foo‘) === Symbol(‘foo‘) // false

Symbol.for(‘foo‘) === Symbol(‘foo‘) // false

Symbol.for(‘foo‘) === Symbol.for(‘foo‘) // true

map

Maps 在 JavaScript 中是一个非常必须的数据结构,在 ES6 之前,我们通过对象来实现哈希表

var map = new Object();

map[key1] = ‘value1‘;

map[key2] = ‘value2’;

实际上 Maps 允许我们对值进行 setget 和 search 操作:

let map = new Map();

> map.set(‘name‘, ‘david‘);

> map.get(‘name‘); // david

> map.has(‘name‘); // true

Maps 更令人惊奇的部分就是它不仅限于使用字符串作为 key,还可以用其他任何类型的数据作为 key:

let map = new Map([

    [‘name‘, ‘david‘],

    [true, ‘false‘],

    [1, ‘one‘],

    [{}, ‘object‘],

    [function () {}, ‘function‘]
]);

for (let key of map.keys()) {

    console.log(typeof key);

    // > string, boolean, number, object, function
}

WeakMaps

在 ES6 之前,为了存储私有变量,我们有各种各样的方法去实现,其中一种方法就是用命名约定:

class Person {

    constructor(age) {

        this._age = age;
    }

    _incrementAge() {

        this._age += 1;
    }
}

但是命名约定在代码中仍然会令人混淆并且并不会真正的保持私有变量不被访问。现在,我们可以使用 WeakMaps 来存储变量:

let _age = new WeakMap();

class Person {

    constructor(age) {

        _age.set(this, age);

    }

    incrementAge() {

        let age = _age.get(this) + 1;

        _age.set(this, age);

        if (age > 50) {

            console.log(‘Midlife crisis‘);
        }
    }
}

一个更实际的实践就是可以 WeakMaps 储存 DOM 元素,而不会污染元素本身:

let map = new WeakMap();

let el  = document.getElementById(‘someElement‘);

// Store a weak reference to the element with a key

map.set(el, ‘reference‘);

// Access the value of the element

let value = map.get(el); // ‘reference‘

// Remove the reference

el.parentNode.removeChild(el);

el = null;

// map is empty, since the element is destroyed

Promises

Promises 可以让我们远离平行的代码:

func1(function (value1) {

    func2(value1, function (value2) {

        func3(value2, function (value3) {

            func4(value3, function (value4) {

                func5(value4, function (value5) {

                    // Do something with value 5
                });
            });
        });
    });
});

转变成垂直代码:

func1(value1)

    .then(func2)

    .then(func3)

    .then(func4)

    .then(func5, value5 => {

        // Do something with value 5

    });

Generators 生成器

就像 Promises 可以帮我们避免回调地狱,Generators 可以帮助我们让代码风格更整洁--用同步的代码风格来写异步代码,它本质上是一个可以暂停计算并且可以随后返回表达式的值的函数。Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。

function* sillyGenerator() {

    yield 1;

    yield 2;

    yield 3;

    yield 4;

}

var generator = sillyGenerator();

console.log(generator.next()); // { value: 1, done: false }

console.log(generator.next()); // { value: 2, done: false }

console.log(generator.next()); // { value: 3, done: false }

console.log(generator.next()); // { value: 4, done: false }

next 可以回去到下一个 yield 返回的值,当然上面的代码是非常不自然的,我们可以利用 Generators 来用同步的方式来写异步操作

function request(url) {

    getJSON(url, function(response) {

        generator.next(response);
    });
}

这里的 generator 函数将会返回需要的数据:

function* getData() {

    var entry1 = yield request(‘http://some_api/item1‘);

    var data1  = JSON.parse(entry1);

    var entry2 = yield request(‘http://some_api/item2‘);

    var data2  = JSON.parse(entry2);
}

通过 yield,我们可以保证 entry1 有 data1 中我们需要解析并储存的数据。

虽然我们可以利用 Generators 来用同步的方式来写异步操作,但是确认错误的传播变得不再清晰,我们可以在 Generators 中加上 Promise:

function request(url) {

    return new Promise((resolve, reject) => {

        getJSON(url, resolve);

    });

}

然后我们写一个函数逐步调用 next 并且利用 request 方法产生一个 Promise:

function iterateGenerator(gen) {

    var generator = gen();

    (function iterate(val) {

        var ret = generator.next();

        if(!ret.done) {

            ret.value.then(iterate);

        }

    })();

}

在 Generators 中加上 Promise 之后我们可以更清晰的使用 Promise 中的 .catch 和 reject来捕捉错误,让我们使用新的 Generator,和之前的还是蛮相似的

iterateGenerator(function* getData() {

    var entry1 = yield request(‘http://some_api/item1‘);

    var data1  = JSON.parse(entry1);

    var entry2 = yield request(‘http://some_api/item2‘);

    var data2  = JSON.parse(entry2);

});

Async Await

当 ES6 真正到来的时候,async await 可以用更少的处理实现 Promise 和 Generators 所实现的异步处理

var request = require(‘request‘);

function getJSON(url) {

  return new Promise(function(resolve, reject) {

    request(url, function(error, response, body) {

      resolve(body);
    });
  });
}

async function main() {

  var data = await getJSON();

  console.log(data); // NOT undefined!
}

main();

在 js 引擎中,它所实现的和 Generators 其实是一样的,我更推荐在 Generators + Promises 之上使用 async await

参考

https://qiutc.me/post/es6-cheatsheet.html

时间: 2024-12-09 18:33:59

ECMAScript 6的相关文章

ECMAScript 5 Array Methods

ECMAScript 5 定义了9个新的数组方法,分别为: 1.forEach();  2.map();  3.filter();  4.every();  5.some();  6.reduce();  7.reduceRight();  8.indexOf();  9.lastIndexOf(); 概述:首先,大多数的方法都接受一个函数作为第一个参数,并为数组里的每个元素(或者一些元素)执行这个函数.在稀疏数组中(索引不以0开始,并且元素不连续),不存在的数组元素不调用函数参数.大多数实例中

前端开发者进阶之ECMAScript新特性--Object.create

前端开发者进阶之ECMAScript新特性[一]--Object.create Object.create(prototype, descriptors) :创建一个具有指定原型且可选择性地包含指定属性的对象 参数:prototype 必需.  要用作原型的对象. 可以为 null.descriptors 可选. 包含一个或多个属性描述符的 JavaScript 对象."数据属性"是可获取且可设置值的属性. 数据属性描述符包含 value 特性,以及 writable.enumerab

ECMAScript基本数据类型

ECMAScript有5种基本数据类型 Undefined.Null.Boolean.Number 和 String. Undefined类型 未声明.声明但未初始化的变量typeof判定数据类型的时候都是 undefined 声明但未初始化的变量可以对其进行undefined值类型可以执行的操作 未声明的变量对其使用非赋值操作都会出错 var JsTest=function(){ var str; console.log(str==undefined);//true console.log(s

ECMAScript 6 小结

一.测试环境 1.node下几乎完全支持ES6,标准浏览器支持部分语法 2.chrome下使用ES6,为了保证可以正常使用大部分语法,需要使用严格模式,即在js开始部分加上'use strict' 3.ff下需要知道测试版本,即在script标签的type属性中加上 'application/javascript:version=1.7' 属性值 二.区别 1.声明变量 var 可以多次声明同一个属性 let 需要在严格模式下才能用,不允许重复声明,没有与解析过程(声明之前调用不是undefin

ECMAscript

ECMAScript 1. ECMAScript ECMAScript:JavaScript的规范 ECMA-262号文件 - JavaScript 循环的方法: var ary = [1,2,3,4,5]; // for循环 for(var i = 0;i < ary.length;i++){ console.log(ary[i]); } // forEach ary.forEach(function(value){ console.log(value); }) // for..in.. fo

Javascript与ECMAScript

我们经常习惯性认为Javascript就是ECMAScript,但其实不是这样的. ECMAScript是一种脚本在语法和语义上的标准. 主要包括:语法.类型.语句.关键字.保留字.操作符.对象. 它与浏览器之间,没有半毛钱关系. 而Javascript是基于ECMAScript标准实现的.Javascript不仅仅包括ECMAScript,它其实还包含了其他东西. Javascript主要由三个部分组成,见下图: 在上面ECMAScript与Javascript的比较中,已经谈了ECMAScr

[Node.js] ECMAScript 6中的生成器及koa小析

原文地址:http://www.moye.me/2014/11/10/ecmascript-6-generator/ 引子 老听人说 koa大法好,这两天我也赶了把时髦:用 n 安上了node 0.11.12,下了个koa开启harmony模式试水.在一系列文档和贴子的教育下,大概认识到: koa 是TJ大神主导的新一代Web框架 koa 的中间件基于ES6的生成器函数(function *)形式 koa的核心流程库是 co,它能很好的解决Pyramid of Doom问题 在接触 Node.j

ECMAScript prototype的一个疑问。

既然是疑问 当然首先要贴一段代码. 背景: 探究js的原型继承模式. 疑惑:为何person1和person2的prototype 居然是相等的. 附: 1.Object.create(proto, [ propertiesObject ]) 参数 proto 一个对象,作为新创建对象的原型.或者为 null. propertiesObject 可选.该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProper

ECMAScript 6初探附查询手册

我用jquery有5.6年了,可以用jq写出网页中超过80%常见的特效 ,对于ECMAScript 6我也是前年才知道的,不过一直没有系统的去研究,只知道是javascirpt的升级版,对它的了解仅此而已. 我是一个70%时间去思考,30%去做事的人,对于我一直从事的web前端来说,我一直认为web前端的终极目的是用户体验,用户体验是一个很无边界的概念,只需要科学的html5+规范的css3+jquery+细节+优化是可以做出体验很好的网页的,是的,这一切都不难,你只需要做到标准和细心. 对于E

ECMAScript 2016 获得批准

ECMA 国际批准了第七版的 ECMAScript 语言规范(ECMAScript 2016).ECMAScript 是标准化的 JavaScript 语言,1997年发布了第一版,1998年和1999年发布了第二和第三个版本.之后 ECMAScript 沉寂 了许多年,直到 Ajax 流行起来后标准工作才再次起步.2009年发布了第五个版本,2015年发布了第六个版本.ECMAScript现在每年发布一个新版规范,ECMAScript 2017已在制定之中. 第七个版本又被称为 ECMAScr