AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

ES 2015-JavaScript EcmaScript 6新特性一览 by 蔡超

发布者 FEer   简介 前端技术
发布于 1436953922191  浏览 8640 关键词 前端, JavaScript 
分享到

第1页

ES 2015

前端 蔡超



第2页

概况



第3页

★ 2015年6⽉月18⽇日定稿! ★ ES6 => ES 2015 ★ NodeJs对ES6⽀支持很差 可以使⽤用io.js 每周更新 ★ 知名框架ES6化 Angular、React(ES7部分⽀支持) ★ ES6 to ES5 ⼯工具 Babel(6500多个Star)



第4页

Arrows function Classes



default + rest + spread let + const



String



Promises



async await



Destructuring



binary and octal literals



Map + Set + Weakmap + Weakset



Proxies



Unicode Iterators



Modules + Module loader Generators



Enhanced Object Literals Symbols reflect api



第5页

Arrows function default + rest + spread

let + const Classes

Map + Set + Weakmap + Weakset Destructuring String

Modules + Module loader Iterators Symbols

Enhanced Object Literals



第6页

let + const



第7页

let + const

• JS的问题:变量声明提升 & 函数声明提升

var n = 1; (function () {

console.log(n); var n = 2; console.log(n); })(); console.log(n); // undefined // 2 // 1



第8页

let + const



• let 是可以认为是var的⼀一个升级版,它把变量锁死在⾃自⼰己的作⽤用域⾥里



// ES5

var a = 1;

if (1 === a) { var b = 2;

}

console.log(a); // 1 console.log(b); // 2

// window console.log(window.a); // 1 console.log(window.b); // 2



// ES6 — let

let a = 1;

if (1 === a) { let b = 2;

}

console.log(a); // 1 console.log(b); // ReferenceError: b is not defined

// window console.log(window.a); // 1 console.log(window.b); // undefined



第9页

let + const

• const与let很像,属于⾃自⼰己作⽤用域内的常量,不可以更改的值,使⽤用 const来做声明

// ES6 — let

const PI = 3.1415926; // 全局的PI常量 {

const PIPI = 3.14; // 本作⽤用域的PI常量 } console.log(PI); // 3.1415926 PI=3; console.log(PI); // 3.1415926 console.log(PIPI); // 3.14



第10页

default + rest + spread



第11页

default + rest + spread

这三项放在⼀一起,是ES6针对函数参数部分的优化改进



第12页

default + rest + spread

• default

为⾏行参提供默认值,在没有参数传⼊入时使⽤用默认值 其他语⾔言很早就有的设定

// ES5 function inc(number, increment) {

// 如果没有increment参数传⼊入,我们默认为1 increment = increment || 1; return number + increment; } console.log(inc(2, 2)); // 4 console.log(inc(2)); // 3

// ES6,使⽤用了默认值 function inc(number, increment = 1) {

return number + increment; }



第13页

default + rest + spread



• default 甚⾄至你还可以放在参数中间启⽤用默认值



function sum(a, b = 2, c) { return a + b + c;

}



console.log(sum(1, 5, 10));



// 16 -> b === 5



console.log(sum(1, undefined, 10)); // 13 -> b as default



第14页

default + rest + spread

• default

默认值除了写常量,变量,还可以接收⼀一个函数返回值

function getDefaultIncrement() { return 1;

}

function inc(number, increment = getDefaultIncrement()) { return number + increment;

}

console.log(inc(2, 2)); // 4 console.log(inc(2)); // 3



第15页

default + rest + spread

• rest 下⾯面让我们写个将所有参数累加的⽅方法,如果使⽤用ES5,需要调⽤用 arguments,可能会这么写:



// ES5 function sum() {

var numbers = Array.prototype.slice.call(arguments), result = 0;

numbers.forEach(function (number) { result += number;

}); return result; }



console.log(sum(1));



// 1



console.log(sum(1, 2, 3, 4, 5)); // 15



第16页

default + rest + spread

• rest

ES6提供了⼀一个叫rest的机制,我们可以理解为余下的所有(参 数),上⾯面累加的函数可以改写为

// ES5 function sum(…numbers) {

var result = 0; numbers.forEach(function (number) {

result += number; }); return result; }

console.log(sum(1)); // 1 console.log(sum(1, 2, 3, 4, 5)); // 15



第17页

default + rest + spread

• rest ES6提供了⼀一个叫rest的机制,我们可以理解为余下的所有(参 数),上⾯面累加的函数可以改写为 注意:⼀一旦使⽤用了rest,⾏行参位置就只能使⽤用rest写法,不能再拆 分参数了,如下就是错误的:

function sum(…numbers, last) // 语法错误



第18页

default + rest + spread

• spread

spread是与上⾯面rest很相关的⼀一个特性,因为都使⽤用了3个点..., rest是⾏行参定义时,spread是实参传⼊入时

// ES6 function sum(a, b, c) {

return a + b + c; } var args = [1, 2, 3];

// ES6 console.log(sum(…args)); // 6

// ES5我们要这么写 console.log(sum.apply(undefined, args)); // 6



第19页

default + rest + spread

• spread

spread是与上⾯面rest很相关的⼀一个特性,因为都使⽤用了3个点..., rest是⾏行参定义时,spread是实参传⼊入时 spread没有rest的⾏行参数量限制问题,可以后⾯面拆分实际参数传 ⼊入,如下:

function sum(a, b, c) { return a + b + c;

} var args = [1, 2];

console.log(sum(…args, 3)); // 6



第20页

String



第21页

• 字符串插⼊入(模板)



String



let x = 1; let y = 2; let sumTpl = `${x} + ${y} = ${x + y}`;

console.log(sumTpl); // 1 + 2 = 3



如上,可以使⽤用 ${变量名} 的语法直接插⼊入变量,有了它,我们可以 扔掉JS模版系统了。



第22页

• 多⾏行字符串



String



let types = `Number String Array Object`; console.log(types); // Number

// String // Array // Object



var types = “Number\nString\nArray\nObject";

console.log(types); // Number // String // Array // Object



第23页

String

• 原⽣生字符串 String.raw

// 输出多⾏行⽂文本 let interpreted = ‘raw\nstring’; // 包含了`\\n`这个转义字符 let esaped = ‘raw\\nstring';

// 使⽤用了 String.raw ⽅方法,把 \n 直接输出,没有被转义 let raw = String.raw`raw\nstring`; console.log(interpreted); // raw

// string console.log(raw === esaped); // true



第24页

• ⽀支持枚举



String



let str = ‘abc'; console.log(str.length); // 3 for (let c of str) {

console.log(c); // a // b // c

}



第25页

String

• 还可以⽤用我们之间讲到的 spread 把字符串很⽅方便的转为数组

let str = 'abcd'; let chars = […str]; console.log(chars); // ['a', 'b', 'c', 'd']



第26页

• 新增的字符串⽅方法



String



// repeat(n)—使字符串重复⽣生成n次 console.log('abc|'.repeat(3)); // 'abc|abc|abc|'



// startsWith(str, starts = 0)—是否从某位置开始某个字串?布尔返回值



console.log('ecmascript'.startsWith('ecma'));



// true



console.log('ecmascript'.startsWith('script', 4)); // true



// endsWith(str, ends = str.length) —是否从某位置以某字符串结束?布尔返回值 console.log('ecmascript'.endsWith('script')); // true console.log('ecmascript'.endsWith('ecma', 4)); // true



// includes(str, starts = 0) : boolean—从某个位置开始是否包含某个字符串



console.log('ecmascript'.includes('ecma'));



// true



console.log('ecmascript'.includes('script', 4)); // true



第27页

String



• Unicode 扩展⽀支持 ⽀支持双16位编码字符 two 16-bit code units



let str = '𠮷';



console.log(str.length);



// 2



console.log(str === '\uD842\uDFB7'); // true



console.log(str.charCodeAt(0)); // 55362 console.log(str.charCodeAt(1)); // 57271



⽀支持字符以UTF-16编码,新的 codePointAt ⽅方法

console.log(str.codePointAt(0)); // 134071 console.log(str.codePointAt(1)); // 57271 console.log(str.codePointAt(0) === 0x20BB7); // true



第28页

Classes



第29页

• ES6以前的(伪)类



Classes



function Animal(name){ this.name = name;

} Animal.prototype.breathe = function () {

console.log(this.name + ‘is breathing’); }



第30页

Classes

• ES6原⽣生⽀支持写类了!

class Animal { constructor(name) { this.name = name; } breathe() { console.log(`${this.name} is breathing`); }

}

function Animal(name){ this.name = name;

} Animal.prototype.breathe = function () {

console.log(this.name + ‘is breathing’); }



第31页

• 作为类当然要⽀支持继承



Classes



class Dog extends Animal { constructor(name) { super(name); } bark() { console.log(`Woof! ${this.name} is barking`); }

}



class Animal { constructor(name) { this.name = name; } breathe() { console.log(`${this.name} is breathing`); }

}



第32页

• 使⽤用⽅方法没有变化



Classes



let puppy = new Dog();



puppy.breathe(); // Animal ⽗父类的⽅方法



puppy.bark();



// Dog ⼦子类的⽅方法



class Dog extends Animal { constructor(name) { super(name); } bark() { console.log(`Woof! ${this.name} is barking`); }

}



第33页

Enhanced Object Literals



第34页

Enhanced Object Literals

• 增强的对象字⾯面量,写法多样,更像⼀一个类

key / value 同名时可以简写

var obj = { // hander: hander的简写 handler,

};



第35页

Enhanced Object Literals

• 增强的对象字⾯面量,写法多样,更像⼀一个类

⽀支持直接定义原型了 __proto__

var obj = { // hander: hander的简写 handler, // __proto__属性 __proto__: theProtoObj,

};



第36页

Enhanced Object Literals

• 增强的对象字⾯面量,写法多样,更像⼀一个类

⽅方法声明简写

var obj = { // hander: hander的简写 handler,

// __proto__属性 __proto__: theProtoObj,

// ⽅方法声明 toString() {

return "d " + super.toString(); }, };



第37页

Enhanced Object Literals

• 增强的对象字⾯面量,写法多样,更像⼀一个类

动态属性名直接写表达式

var obj = { // hander: hander的简写 handler,

// __proto__属性 __proto__: theProtoObj,

// ⽅方法声明 toString() {

return "d " + super.toString(); },

// 动态属性名 [ "prop_" + (() => 42)() ]: 42 };



第38页

Enhanced Object Literals

ES3-5的年代,我们还在分不清JSON和Object的区别 看了上⾯面的⾼高级Object,⼤大家有些体会了不?



第39页

Arrow function



第40页

Arrow function 牢记:箭头函数总(就)是个匿名函数



第41页

Arrow function



• 语法规则



([param] [, param]) => { statements

}

• 表达式体 / 块体

param => expression

(param1, param2) => { block }



// ⽆无参数 () => { … }

// 单参数,括号可以省略 x => { … }

// 多参数 (x, y) => { … }

// 块体 x => { return x * x }

// 表达式体,同上 x => x * x



第42页

Arrow function

• 举个栗⼦子 Array的Map⾼高阶函数

// ES5 [3, 4, 5].map(function (n) {

return n * n; });

// ES6 箭头函数这么写 [3, 4, 5].map(n => n * n);



第43页

Arrow function

• 箭头函数会⾃自动帮我们处理this 😊

// ES5 function FancyObject() {

var self = this; self.name = 'FancyObject'; setTimeout(function () {

self.name = 'Hello World!'; }, 1000); }

// ES6 Arrow Function function FancyObject() {

this.name = 'FancyObject'; setTimeout(() => {

this.name = 'Hello World!'; // this直接使⽤用的是FancyObject }, 1000); }



第44页

Destructuring



第45页

Destructuring

解构可以让我更灵活更⾼高效的写代码,它允许按照模 式匹配绑定代码,包括数组和对象。它很像⼀一个简单 对象查找,当没有找到值时,返回undefined。



第46页

Destructuring

• Array 数组部分 ES6提供了解构的⽅方式,让我们更⽅方便更灵活的将数组值拆给每个 单独的变量



// ES5 var point = [1, 2]; var xVal = point[0],

yVal = point[1];

console.log(xVal); // 1 console.log(yVal); // 2



// ES6 let point = [1, 2]; let [xVal, yVal] = point;

console.log(xVal); // 1 console.log(yVal); // 2



第47页

Destructuring

• Array 数组部分 ES6提供了解构的⽅方式,让我们更⽅方便更灵活的将数组值拆给每个 单独的变量 对换位置也是可以的



// ES6 let point = [1, 2]; let [xVal, yVal] = point;

console.log(xVal); // 1 console.log(yVal); // 2



// ES6 let point = [1, 2]; let [xVal, yVal] = point; [xVal, yVal] = [yVal, xVal];

console.log(xVal); // 2 console.log(yVal); // 1



第48页

Destructuring

• Array 数组部分 ES6提供了解构的⽅方式,让我们更⽅方便更灵活的将数组值拆给每个 单独的变量 对换位置也是可以的 或者当我们忘掉了⼀一个变量的时候,也是OK的

let threeD = [1, 2, 3]; let [a, , c] = threeD; console.log(a); // 1 console.log(c); // 3



第49页

Destructuring

• Array 数组部分

ES6提供了解构的⽅方式,让我们更⽅方便更灵活的将数组值拆给每个 单独的变量 对换位置也是可以的 或者当我们忘掉了⼀一个变量的时候,也是OK的 甚⾄至是嵌套的⼆二维数组

let nested = [1, [2, 3], 4]; let [a, [b], d] = nested; console.log(a); // 1 console.log(b); // 2 console.log(d); // 4



第50页

Destructuring

• Object 对象部分

对象的解构,相对于数组就更好理解了,我们使⽤用对象字⾯面量中 赋值符号(冒号)左边的key直接⽤用来赋值

let point = { x: 1, y: 2

}; let { x: a, y: b } = point;

console.log(a); // 1 console.log(b); // 2



第51页

Destructuring

• Object 对象部分

对象解构像数组⼀一样,同样⽀支持嵌套赋值

let point = { x: 1, y: 2, z: { one: 3, two: 4 }

}; let { x: a, y: b, z: { one: c, two: d } } = point;

console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(d); // 4



第52页

Destructuring

• 数组、对象混合结构

let mixed = { one: 1, two: 2, values: [3, 4, 5]

}; let { one: a, two: b, values: [c, , e] } = mixed;

console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(e); // 5



第53页

Destructuring

• 数组、对象混合结构

甚⾄至,我们的function返回值也可以直接解构赋值

function mixed () { return { one: 1, two: 2, values: [3, 4, 5] };

} let { one: a, two: b, values: [c, , e] } = mixed();

console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(e); // 5



第54页

Destructuring

• 特别说明

如果解构和需要赋值的变量数量不匹配,那么对应位置的变量将设置 为undefined

let point = { x: 1

}; let { x: a, y: b } = point; console.log(a); // 1 console.log(b); // undefined



第55页

Destructuring

• 特别说明

如果我们忘了let / const / var的话,会抛出⼀一个错误

let point = { x: 1

}; { x: a } = point; // 抛出错误,a没有被定义

但如果我们外⾯面套个括号的话……

let point = { x: 1

}; ({ x: a } = point); console.log(a); // 1



第56页

Iterators



第57页

• for of 新的 for 循环



Iterators



const arr = [1, 2, 3, 4, 5]; for (let item of arr) {

console.log(item); // 1 // 2 // 3 // 4 // 5

}



第58页

Iterators

• for of 新的 for 循环

当然,for of循环⾥里可以使⽤用循环控制语句

const arr = [1, 2, 3, 4, 5]; for (let item of arr) {

if (item > 4) { break;

} if (0 !== item % 2) {

continue; } console.log(item); // 2

// 4 }



第59页

Iterators

for of的内部实现,其实是使⽤用⼀一个枚举器实现的。 像Java和C#,ES6也为我们提供了可以⾃自定义的枚举器,还内置了 ⼀一些可以枚举的对象,如 String, Array, TypedArray, Map and Set.

说到枚举器,我们先来看下这个: Symbol



第60页

Iterators

• Symbol

ES6中完全的新内容Symbol符号是⼀一个唯⼀一的、不可改变的数据类 型,可以⽤用来做对象的属性,来标⽰示唯⼀一对象,相当于数据库表中的 ID字段,unique。

// Symbol let s1 = Symbol('abc'); let s2 = Symbol(‘abc');

console.log(s1 !== s2); // true console.log(typeof s1); // ‘symbol'

let obj = {}; obj[s1] = 'abc'; console.log(obj); // Object { Symbol(abc): 'abc' }



第61页

• Symbol

我们可以使⽤用 Symbol.iterator ,配合next()⽅方法 实现我们⾃自定义 的枚举器,如:



Iterators

let random1_10 = function (items = 1) { return { [Symbol.iterator]() { let cur = 0; return { next() { if (cur === items) { return { done: true } } ++cur; return { done: false, value: Math.floor(Math.random() * 10) + 1 } } } } };

}; for (let n of random1_10(5)) {

console.log(n); // prints 5 random numbers }



第62页

Map + Set + WeakMap + WeakSet



第63页

Map + Set + WeakMap + WeakSet

ES6中新添加的四种数据集合类型,提供了更加⽅方便 的获取属性值的⽅方法,不⽤用像以前⼀一样⽤用 hasOwnProperty来检查某个属性是属于原型链上的 呢还是当前对象的。



第64页

Map + Set + WeakMap + WeakSet

• Set 是 ES6 新增的有序列表集合,它不会包含重复项   var s = new Set();

s.add("hello").add("goodbye").add("hello");

 s.size; // 2,重复的不会再次保存; s.has(“hello”); // true

• Map 是 ES6 新增的有序键值对集合, key 和 value 都可以是任意类型, 可以被 for … of 遍历

var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s); // 34



第65页

Map + Set + WeakMap + WeakSet

• WeakMap / WeakSet 最⼤大的好处是可以避免内存泄漏,仅保持弱引 ⽤用,也就是说它不阻⽌止垃圾回收。垃圾回收会回收掉仅在Weak类型 引⽤用的对象。⺫⽬目前使⽤用场景还不多,将来应该会很有⽤用。

var ws = new WeakSet(); ws.add({ data: 42 }); // 被add的对象没有其他引⽤用,所以不会存⼊入ws中 var wm = new WeakMap(); wm.set(s, { extra: 42 }); wm.get(s); // undefined



第66页

Module



第67页

Module

• NodeJS(CommonJS)中的模块

// baz.js let baz = 'baz'; export baz; // 上⾯面两⾏行可以合并写成 export let baz = 'baz'; // app.js import {baz} from "baz.js";



第68页

Module

• NodeJS(CommonJS)中的模块

⾼高级混合⽤用法,使⽤用了 * / as / 解构

// lib/math.js export function sum(x, y) {

return x + y; } export var pi = 3.141593;

// app.js 主App⽂文件,import时使⽤用了*和as,下⾯面代码就可以使⽤用.符号了 import * as math from "lib/math"; alert("2π = " + math.sum(math.pi, math.pi));

// otherApp.js 其他⽂文件,解构(Destructuring)⽅方式直接赋值,上⾯面介绍过了 import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi));



第69页

Module

• NodeJS(CommonJS)中的模块

default 和 * 关键字

// lib/mathplusplus.js export * from "lib/math"; export var e = 2.71828182846; export default function(x) {

return Math.exp(x); }

// app.js import exp, {pi, e} from "lib/mathplusplus"; alert("2π = " + exp(pi, e));



第70页

Promise

Generators

Koa



第71页

Babel 使⽤用

https://babeljs.io/repl/



第72页

Q&A



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。