用简单的方法学习ES6

ES6 简要概览

这里是ES6 简要概览。本文大量参考了ES6特性代码仓库,请容许我感谢其做者@Luke Hoban的卓越贡献,也感谢@Axel Rauschmayer所做的[优秀书籍]//exploringjs.com/es6/)。javascript

起初当我据说ES6时,我花了不少精力去消化学习其概念和基础知识。我经历了这些,但愿大家无需重蹈覆辙。所以我写下了这篇对ES6及其新特性的简要介绍,全部知识点都解释得通俗易懂,简明扼要,对于像我这样的新人很是友好。php

简介

ES6,也称做ECMAScript 2015,是JavaScript的下一代版本,在2015年6月正式标准化。ES6是该语言自2009年的ES5以来的一次重大更新。css

  • 这是一门全新的语言吗?:绝对不是!它就是咱们所了解的JavaScript,只不过拥有了更优雅的语法和更多特性。
  • 这是否意味着我现有的JavaScript代码不久就将变得不可用了?:并不是如此!若是是那样的话,对整个网站将是巨大的损失!JavaScript一直都是向后兼容的。好比,新的特性将会被添加,而现存特性将会变得更强大。这叫作惟一的JavaScript
  • 它的目标是什么?:整体来讲是成为了一门更好的语言!它让咱们的代码更快,更安全,更搞笑。
  • ES6以后还会有什么?:会出现ECMAScript 7等等后续版本。TC39计划每一年发布一个ECMAScript的新版本。好比,从如今开始,ECMAScript版本将会做相对较小的升级。所以,当你想开始学ES7和后续版本时,你如今所学的关于ES6的一切将会派上用场。

安装

这个部分是为那些还不熟悉命令行的Web设计开发者准备的。若是你已经知道如何安装node.js 和 Babeljs,以及ES6编译器,你能够跳过这部分。html

我是否须要安装一些东西?是的!因为ES6是新的,浏览器还没有支持其大多数特性。但咱们无需等待。咱们能够在node.js 和 Babeljs, 以及S6编译器的帮助下开始编写ES6代码Babeljs将会将ES6语法转换为ES5,这样现有的浏览器就能够解释咱们的代码了,就好像咱们一开始就是用ES5编写的同样。这是否是很酷?让咱们来看看全部这一套是如何安装的,而后开始编写代码。java

  • 首先下载和安装node.js到你的机器上。
  • 打开终端/命令行,输入npm install --global babel。按下回车运行该命令,而后第一次安装Babeljs到你的机器。Babeljs就是ES6的编译器。
  • 运行命令: npm install -g browserify。若是你想使用ES6模块加载器语法,须要把Browserify也装上。Browserify使你能在独立的JavaScript文件中编写更加模块化的代码,而后将它们打包,最后让你的HTML页面只需引用一个JavaScript文件。
  • 运行命令:cd path/to/my/project,将路径更改成你的项目路径。
  • 运行命令:babel src --out-dir build。这条命令会将'src'文件夹下的全部 .js 后缀的文件从ES6转换为ES5语法,而后将转换后的文件放入'build'目录下。

如今你已经准备好了,你能够将新的转换后的.js文件引入你的HTML页面,浏览器就能够像往常同样正常运行你的代码。node

ES6 特性

字符串,数组,及对象的新增API

在ES6中,咱们有许多新增的库,包括核心的Math库,数组转换帮助工具和用于拷贝的Object.assign()jquery

'hello'.startsWith('hell'); // => true 'hello'.endsWith('ello'); // => true 'hello'.includes('ell'); // => true 'doo '.repeat(3); // => 'doo doo doo ' Array.from(document.querySelectorAll("*")); // => 返回一个真实的数组 Array.of(1, 2, 3); // => 和 new Array(...)类似, 可是不须要指定单参数 [0, 0, 0].fill(7, 1); // => [0,7,7] [1, 2, 3].findIndex(x => x == 2); // => 1 ['a', 'b', 'c'].entries(); // => 迭代器 [0, 'a'], [1,'b'], [2,'c'] ['a', 'b', 'c'].keys(); // => 迭代器 0, 1, 2 ['a', 'b', 'c'].values(); // => 迭代器 'a', 'b', 'c' Object.assign(Point, { origin: new Point(0,0) }); // => 为'Point'对象添加新属性. 

Symbol

Symbol是ES6中的一种新的原始数据类型。它们是做为独有ID使用的字符。你能够经过工厂函数Symbol()创造symbol字符。它们都是独一无二的。每次咱们建立一个新的symbol,咱们其实是建立了一个新的独一无二的标识符,它不会与咱们项目中其余任何变量名、属性名冲突。这就是为何某些场景下它颇有用的缘由。例如,咱们可使用它定义一个常量。git

在ES5中,咱们之前会使用两个不一样的对无二的字符串来定义常量。咱们会不得不依赖于字符串!但众所周知,字符串并不具有惟一性。咱们可能在偶然的时机改变它,或在不一样的地方输入它们,这些操做会使咱们的常量的行为崩坏。可是如今,咱们能够很容易地使用Symbol()来定义常量,并能确保每次咱们调用Symbol()时都会产生一个在咱们项目中独一无二的标识符,而且永远不会和其余属性名产生冲突。这很酷!es6

const COLOR_RED = Symbol(); const COLOR_ORANGE = Symbol(); console.log( 'each Symbol() is always unique: ', Symbol() === Symbol() ); // => 没错,这样也会返回false. // 它也能够帮咱们为对象和类建立独一无二的动态的方法。 const MY_KEY = Symbol(); let obj0 = {}; obj0[MY_KEY] = 123; console.log('my dynamic object method: ', obj0[MY_KEY]); // => 123 

扩展阅读

模板字符串

模板字符串为构造字符串提供了语法糖。字符串自己被撇号包裹,字符串中插入的表达式使用${var}分隔。模板字符串一般用来建立字符串。github

// 多行字符串
const HTML5_SKELETON = `
<!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> </html>`; // 内嵌变量绑定 let name = 'Bob', time = 'today'; let greeting = `Hello ${name}, how are you ${time}?`; // 与标签模板一块儿使用,生成的原始字符串将包含模板字符串中的全部转义字符和反斜杠。 let str = String.raw`This is a text with multiple lines. Escapes are not interpreted, \n is not a newline.`; 

扩展阅读

Let + Const

ES6提供了两种声明变量的方式:let 和 const,它们几乎替代了ES5中使用var声明变量的方式。letvar的工做方式很像,可是它声明的变量是有块做用域的,它只在于当前的块做用域中有效。而var声明的变量是在函数做用域内有效。

function func(randomize) { if (randomize) { let x = Math.random(); // 注意:变量x只存在于这个if做用域中 var y = Math.random(); // 可是变量y能够在整个func函数中访问到 } // 块做用域意思是:咱们能够在一个函数中保护一个变量。好比,这里的x与上述的x没有任何关系。 let x = 5; return y; } 

const 和 let工做原理相似,可是你声明变量的同时必须当即用一个不会再改变的值对其进行初始化。

const a = 123; 

注意const 陷阱!const只保证变量自身是永恒不变的,若是变量是一个对象,则其属性仍然是可变的,相应的解决办法就是JavaScript的 freeze() 方法。

const freezObj = Object.freeze({}); 

解构

解构容许咱们在支持匹配数组和对象的条件下,使用模式匹配进行绑定。 解构其实是一种从存储于对象和数组(多是嵌套存储)的数据中提取值的简便方法。

// 让咱们更好地理解解构: let obj1 = {}; obj1.first = 'Jane'; obj1.last = 'Doe'; // 这是咱们构造对象数据的方式 let f1 = obj1.first; let l1 = obj1.last; // 这是咱们从对象中提取数据的方式 // 咱们也可使用对象字面量来构造: let obj2 = { first: 'Jane', last: 'Doe' }; // 解构和它很相似。解构就是构造的对立面。它使咱们提取数据变得更加容易。 let { first: f2, last: l2 } = obj2; // 如今咱们得到了变量f2和l2。 // 解构对数组一样适用 let [x1, y1] = ['a', 'b']; // => x1 = 'a'; y1 = 'b' // 用计算过的值做为属性 const FOO = 'foo'; let { [FOO]: f4 } = { foo: 123 }; // => f4 = 123 

咱们也可为解构选择一种模式。注意:值得一提的是,当咱们使用解构赋值时,咱们须要声明要从数组或对象中抽取的变量。好比,在下面的例子中,咱们要从obj3中抽取foo,并将其存储为变量f3。咱们只建立了访问对象的foo属性的模式,而且只声明了该属性,由于咱们只须要用到它。

let obj3 = { a: [{ foo: 123, bar: 'abc' }, {}], b: true }; let { a: [{foo: f3}] } = obj3; // => f3 = 123 

解构赋值也能够有默认值:

let [x3 = 3, y3] = []; // => x3 = 3; y3 = undefined let {foo: x4 = 3, bar: y4} = {}; // => x4 = 3; y4 = undefined // 固然,默认值也能够是函数(执行的结果 -- 译者注): function log() { return 'YES' } let [aa=log()] = []; // Default values can refer to other variables in the pattern.默认值能够指向模式中的其余变量,但它们的顺序相当重要!如下写法会产生引用错误: // let [x=y, y=3] = []; // 为何呢?由于当x指定y为其默认值时,y尚未被定义。 let [xx=3, yy=xx] = []; 

解构也能够用于for...of循环。**注意: **在ES6中有一种新型的循环,for...of。在ES5以前,当咱们想要遍历一个数组时,会使用for,ES5中有一个forEach()方法帮助咱们达成目的。如今的for...of更易用。

// 使用for...of循环数组示例 let arr = ['a', 'b', 'c']; for ( let item of arr ) { //console.log(item); } // 经过使用新的数组方法 entries()和解构赋值,咱们能够获得数组中每一个元素的索引和值。 for ( let [index, item] of arr.entries() ) { //console.log(index + '. ' + item); } // 也可使用下面的方法实现 for ( {name: n, age: a} of arr ) { // do something } // 数组模式对可迭代对象都有效 let [x2,...y2] = 'abc'; // => x2='a'; y2=['b', 'c']; 展开运算符'rest' let [,,x] = ['a', 'b', 'c', 'd']; // => x = 'c'; 能够省略元素 

好,那么除此以外,解构赋值还能用于哪些场景呢?

// 用于分割数组 let [first1, ...rest1] = ['a', 'b', 'c']; // 返回多个值 function testing() { return {element: undefined, index: -1}; } 

扩展阅读

默认值和展开运算符

ES6提供了一个新的更好的定义函数参数默认值的方式:

// 在ES5中,你是这样定义参数的默认值的: function foo(x, y) { x = x || 0; y = y || 0; // do something } // ES6用更好的语法来实现: function foo(x=0, y=0) { // y is 0 if not passed (or passed as undefined) } // 经过ES6,你能够在定义参数时使用解构赋值,代码会变得更简洁: function selectEntries1({ start=0, end=-1, step=1 } = {}) { // do something } // 上述函数与这个等同: function selectEntries2(options) { options = options || {}; var start = options.start || 0; var end = options.end || -1; var step = options.step || 1; // do something } 

ES6也支持rest展开运算符:

function format(pattern, ...params) { return params; } format('a', 'b', 'c'); // ['b', 'c'] // params是一个数组 // ES6 中咱们有展开运算符'...'。 // 在ES5中,咱们使用apply()来将数组中的元素转成参数。 Math.max.apply(null, [-1, 5, 11, 3]); // 如今,咱们很容易就能够实现这个功能,由于展开运算符会提取它的每一项,而后将其转换到参数中。 Math.max(...[-1, 5, 11, 3]); 

扩展阅读

箭头函数和this关键字

箭头函数是使用=>语法简写的函数。可是与其余函数不一样的是,箭头函数包裹的内部代码共享同一个this关键字。

函数体是表达式:

var evens = [0,2,4]; // 如下两种写法效果相同: var odds = evens.map(v => v + 1); var odds = evens.map(function(v){ return v + 1; }); // 如下两种写法效果相同: var nums = evens.map((v, i) => v + i); var nums = evens.map(function(v, i){ return v + i; }); 

函数体是声明:

var fives = []; nums.forEach(v => { // 看见了吗,对于更复杂的声明,咱们能够把全部东西放进大括号{}中,就像咱们使用普通函数那样。 if (v % 5 === 0) fives.push(v); }); 

关键字this:

var bob = { _name: 'Bob', _friends: [], printFriends() { this._friends.forEach(f => // 'this' 关键字就指向'bob'对象,而不是指向这个闭包做用域自己。 console.log(this._name + ' knows ' + f)); }, }; class UiComponent { constructor() { let button = document.getElementById('myButton'); button.addEventListener('click', () => { // 经过使用箭头函数,'this'关键字就指向咱们的'UiComponent'类,而不是闭包。这是ES6提供的很棒的特性。在这种场景下,咱们不再须要使用bind()了。 this.handleClick(); }); } handleClick() { console.log('CLICK'); } } 

ES2015的类是一种基于原型的简单语法糖。

class Person { // 当一个类初始化时,会自动调用构造函数。 constructor(fname, lname) { // 类内部只能包含方法,而不能包含属性,所以咱们须要在构造函数内部设置咱们的属性。 this.fname = fname; this.lname = lname; } } class Employee extends Person { constructor(fname, lname, name = 'no name') { // 在继承类中,必须调用super()才能使用'this'关键字去定义属性,好比this.name. 以及,若是咱们不调用super(),会获得引用错误。 super(fname, lname); if (name === 'no name') this.name = this.fname + ' ' + this.lname; } setJob(title) { this.job = title; } static greeting() { return 'Hello World!'; } // 同时,类智能让咱们建立静态方法,而不能建立静态数据属性。可是咱们能够建立一个静态的getter函数。 static get JOHN() { return new Employee('John', 'Doe'); } // Getters and setters get prop() { return this.prop; } set prop(value) { this.prop = value; } // 计算事后的方法名 ['my'+'Method']() { // do something } } var john = new Employee('John', 'Doe'); john.setJob('Designer'); console.log('Class-> Employee class, just initialized: ', Employee.JOHN); console.log('Class-> Employee class, greeting: ', Employee.greeting()); console.log('Class-> John: ', john); 

扩展阅读

加强的对象字面量

对象字面量被扩展以支持在构造时以foo: foo的简写形式设置原型,定义方法和调用上层函数。

let first = 'Jane'; let last = 'Doe'; let propKey = 'foo'; let obj = { // 方法的定义 myMethod(x, y) { // do something }, // 属性值简写,以下: // let obj = { first, last }; // 效果同下: // let obj = { first: first, last: last }; first, last, // 计算后的属性值: [propKey]: true, ['b'+'ar']: 123, ['h'+'ello']() { // console.log(obj.hello()); return 'hi'; }, // Setter和Getter函数 get sth() { console.log('Object Literal-> ', 'sth getter'); return 123; }, set sth(value) { console.log('Object Literal-> ', 'sth setter'); // 返回值被忽略 } }; // 对象中的新方法 // 对象中最重要的新方法就是assign(). Object.assign(obj, { bar: true }); // 它为咱们的对象新增参数。 console.log('Object Literal-> ', JSON.stringify(obj)); // {"first":"Jane","last":"Doe","foo":true,"bar":true,"sth":123} 

迭代器与for..of循环

ES6 为遍历引入了新的接口,iterable(Iterable 实际上意味着任何东西均可以被重复)。数组,字符串,Map对象,Set对象,DOM数据结构(正在使用中的)都是可迭代的iterable对象。

所以,用简单的话来讲,迭代器就是一种结构,每次调用它时都会按序列返回下一个结果。例如数组的entries()方法。每次咱们调用arr.entries(),它都会返回数组中的下一项。

注意:有的可迭代结构并非什么新鲜事情,例如for循环。可是,我这里只是想解释迭代协议是什么,使它的概念更清晰,而且引入关于它的ES6新特性。

经过迭代协议接收数据的语言构造:

// 解构其实是在作迭代的工做(重复性的工做)来从数组中提取数据。完成这个目标是以一个特别的模式进行重复性的工做。 let [a,b] = new Set(['a', 'b', 'c']); // for-of显然是可迭代的。 for (let x of ['a', 'b', 'c']) { console.log('for-of iteration-> ', x); } let arr2 = Array.from(new Set(['a', 'b', 'c'])); // => Array.from() let arr3 = [...new Set(['a', 'b', 'c'])]; // => 展开运算符 (...) let map0 = new Map([[false, 'no'], [true, 'yes']]); // => Maps的构造函数 let set0 = new Set(['a', 'b', 'c']); // => Sets的构造函数 // Promise.all(iterableOverPromises).then(); // Promise.all() // Promise.race(iterableOverPromises).then(); // Promise.race() // yield* 也是可迭代的 // 注意:当咱们想建立一个nGenerator函数时,'yield' 与Generators相关 // (Generator 是ES6中的新特性) 

让咱们来使用迭代器:

let arr4 = ['a', 'b']; let iter = arr4[Symbol.iterator](); //咱们经过键为Symbol.iterator的方法创造了一个迭代器 // 而后咱们重复调用迭代器的next()方法来检索每一项。 // 在数组内部: iter.next(); // returns an object: { value: 'a', done: false } iter.next(); // { value: 'b', done: false } iter.next(); // { value: undefined, done: true } // 注意:布尔属性'done'暗示了item序列是否到达了末尾。 

看见了吗?这其实有一点像循环。它每次都返回一个新的东西。注意:迭代协议的一个关键特性就是它的有序性:迭代器自己每次只返回一个值,这意味着若是一个迭代的数据结构是非线性的(好比树),迭代器会对其进行线性化。

如今,让咱们在对象中使用Symbol,使其行为表现像一个迭代器同样:

let iterableObject = { // 咱们的对象必需要有一个动态方法,其实是这个动态方法在使用Symbol原始类型。正如咱们所知,Symbol老是独一无二的,这也正是咱们的使用场景,利用它为咱们的类建立一个独一无二的动态方法。 [Symbol.iterator]() { let data = ['hello', 'world']; let index = 0; // 如今咱们的迭代器方法必须返回一个含有next()方法的对象 return { // Here is our iterator logic! In our example here, we check 'index' // variable and act accordingly based on its value.这就是咱们的迭代器逻辑!在这个例子中,咱们检验了'index'变量和基于它的值的表现。 next() { if (index < data.length) { return { value: data[index++] }; } else { return { done: true }; } } }; } }; // 这就是咱们如何使用迭代对象的方法。 for (let x of iterableObject) { // x每次都不一样。第一次循环它是'hello',第二次是'world'. console.log('iterableObject-> ', x); } 

注意:正如咱们所知,咱们在对象中使用了symbol做为方法的键名。这个独一无二字符制造器使对象可迭代,而且使咱们可使用for...of循环。酷~如今咱们已经在咱们的代码里建立了一个定制的迭代对象(或类),这使咱们能够在项目中是的迭代部分的代码更简单。

若是以上可迭代对象是一个真实的样本,它可能在项目中很是有用。对我来讲没有必要把全部逻辑都放进for...of循环来作一个迭代的工做,我只须要建立一个有意义的可迭代类,而后把个人逻辑都放在其中,而后我就能够在不一样的地方用for...of循环使用个人类,而且能够很简单地实现迭代工做。很简单吧~这将使个人代码更简洁。

扩展阅读

模块

组件定义中,对模块的语言层面的支持。从流行的JavaScript模块加载器(AMD, CommonJS)整理的模式。在ES6中,模块存储于文件。每一个文件都是一个模块,每一个模块也都是一个文件。

// lib/math.js // 咱们能够从文件中导出任何变量或函数。 export function sum(x, y) { return x + y; } export var pi = 3.141593; // app.js // 从其余文件中引入咱们想要的任何东西 import * as math from "lib/math"; // 如今,咱们能够像下面这样访问咱们从math.js导出的任何东西: alert("2π = " + math.sum(math.pi, math.pi)); // otherApp.js // 咱们也能够明确指明要引入的函数而不是用一个通用的名字。 import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi)); 

也容许有一个单独的默认输出。Node.js社区中,有不少只导出一个值的模块。咱们可让模块只导出一个类或函数。

// myFunc.js // 固然,咱们导出的函数也能够有一个名称:export default function foo() {} export default function() { } import myFunc from 'myFunc'; myFunc(); // MyClass.js // 以及咱们导出的函数固然也能够有一个名称: export default class Bar {} export default class { } import MyClass from 'MyClass'; let inst = new MyClass(); 

正如咱们所知,在 ES5代码里,不会经过库(相似于RequireJS, Browserify 或 Webpack)来使用模块,其模块模式很是流行,是基于IIFE(当即执行函数)的。它的优势就是明确将共有和私有部分区分开来了.

// 在ES5中如何合理建立模块: // my_module.js var my_module = (function () { // 私有模块的变量 var countInvocations = 0; function myFunc(x) { countInvocations++; } // 经过模块导出: return { myFunc: myFunc }; }()); // 该模块模式产生了一个全局变量,它的使用以下: my_module.myFunc(33); 

在ES6中,模块是内建的,这就是为何使用它们的门槛很是低的缘由:

// 如何在ES6中合理建立模块: // my_module.js // 私有模块的变量: let countInvocations = 0; // 导出模块 export function myFunc(x) { countInvocations++; } 

扩展阅读

四种数据结构:Map,Set,WeakMap,WeakSet

对于通用算法很高效的数据结构。接下来的四种数据结构是ES6中新增的:MapWeakMapSetWeakSet

Map ES5中缺失的是一种值到值的映射。ES6 的 Map数据结构让你能使用任意值做为键,非常一种很流行的作法。

// 建立一个空的Map let map = new Map(); // 咱们也能够在初始化时就填充map为其赋值: let map = new Map([ [ 1, 'one' ], [ 2, 'two' ] ]); // Map的set()方法时可链式调用的。所以咱们也能够像这样填充map赋值: let map = new Map().set(1, 'one').set(2, 'two'); // 任意值,甚至是一个对象,均可以做为键。 // 若是咱们将要得到的值因为某种缘由是undefined,那咱们也能够设置或运算符:map.get(KEY) || 0; const KEY = {}; map.set(KEY, 123); map.get(KEY); // => 123 map.has(KEY); // => true map.delete(KEY); // => true map.size; // => 1 map.clear(); // => 清空map // keys()返回一个Map中的键可迭代的对象。好比咱们能够在一个for-of循环中使用它。 map.keys(); // values() 返回一个Map中的值可迭代的对象。 map.values(); // 返回一个Map中的键值对[key,value]可迭代的对象。 // 注意:咱们能够在for-of循环中使用解构,同时访问到keys和values(键-值),就像咱们用数组的entries()方法能作的那样。 map.entries(); 

WeakMap: 是一种防止其键被垃圾回收机制回收的Map。这意味着你能够用对象协调数据而不须要担忧内存泄漏。WeakMap是一种keys必须为对象,值能够为任意值的数据结构。它有同Map同样的API,惟一一点显著差异是:你不能对内容进行迭代,不管是keyvalue,仍是entries。你也不能清除WeakMap

Set: Set也是 ES5 所没有的数据结构。有两种可能会用到 Set 的地方:

  • 使用对象的key去存储字符串集合的元素。
  • 在数组中存储任意的集合元素:经过indexOf()来检验是否包含某个元素,经过filter()删除元素等等。这不是一个快速解决办法,可是很容易实现。一个须要知晓的地方是,indexOf()没法找出值为NaN的元素。

ES6 的 Set 数据结构对任意值的操做而言很奏效,并且能正确处理NaN

let set = new Set(); // 咱们也能在初始化时就填充Set的值。 let set = new Set(['red', 'green', 'blue']); // Setadd()方法是可链式调用的。所以咱们能够像这样为set赋值: let set = new Set().add('red').add('green').add('blue'); set.add('red'); set.has('red'); // => true set.delete('red'); // => true set.size; // => 1 set.clear(); // => 清空set

WeakSet: Set能够防止其元素被垃圾回收机制回收。

注意: 为何MapSet都是具有size属性而不是像数组那样用length属性呢?这个不一样之处的缘由在于length是对序列而言的,序列这种数据结构是有索引的,像数组这样。size属性是对于集合而言的,它们一般是无序的,像MapSet这样。

扩展阅读

Promise对象

Promise对象是用于异步编程的库。咱们已经熟悉了JavaScript中的promise模式。可是在一些简单场景下,它实际上使得异步的行为更简单。咱们能够设置一个新的promise,在其中编写任何一部行为。好比ajax调用或timeout定时器等等。

function getJSON (url) { let promise = new Promise(function (resolve, reject) { // OK,如今咱们能够在promise中编写咱们的异步行为代码了。好比ajax调用。 // resolve(value); // 若是咱们的ajax调用成功,会调用resolve()并传递必要的参数给它。参数是什么呢?由咱们本身根据咱们的异步工做而决定。 // 好比,对于ajax工做,jquery的ajax()方法在其成功加载文件后会调用咱们的成功回调函数。它也会传递一个参数,就是它实际加载的数据。 // 所以咱们这儿的参数就是这个数据。 // reject(error); // 若是失败,咱们会调用reject(),而且传递必要的参数给它。 }); return promise; // r记得将promise返回 } // 这就是咱们使用promise的方式。 // 当promise状态转为resolved时,它的then()方法将会被调用。当它的状态转为rejected时,catch()方法将会被调用。 getJSON('promised.json') .then(value => {}) .catch(error => {}); // 注意:then()方法也有可选的第二个参数,实际上就是发生的错误。这部分代码和上述相同。咱们能够用任意一个。 getJSON('promised.json') .then(value => {}, error => {}); // 咱们也能够链式使用promise。 then()方法会返回一个新的Promise对象Q。 getJSON('promised.json') .then(value1 => 123) // 不管第一个then()返回了什么,它均可以做为第二个then()的参数。 .then(value2 => {}); // 所以'value2'等于123. // 在链式调用中,若是任意一个promise失败,咱们仍然经过在发生失败的promise的catch()方法返回一个默认值来继续执行调用链。 getJSON('promised.json') .catch(() => 'default value') // 不管第一个then()返回了什么,它均可以做为第二个then()的参数。 .then(value2 => {}); // 所以'value2'等于'default value'. // 咱们也能够手动抛出异常,它会被传递给下一个错误处理器。 getJSON('promised.json') .then(value => {throw new Error();}) .then(err => {}); // 有了可链式调用的promise,如咱们所知,咱们能够很轻松地作下面这样的事,拥有嵌套的promise: asyncFunc1() .then(function (value1) { asyncFunc2() .then(function (value2) { // do something else... }); }); // 或者将其扁平化,像下面这样: asyncFunc1() .then(function (value1) { return asyncFunc2(); }) .then(function (value2) { // do something else... });

著做权归做者全部。
商业转载请联系做者得到受权,非商业转载请注明出处。
原文: https://www.w3cplus.com/javascript/lets-learn-ecmascript-6-basics-in-simple-terms.html © w3cplus.com

相关文章
相关标签/搜索