ES6

ES6教程

对象字面量

  • 方法属性

    let obj = {
    // before
    foo: function() {
    return 'foo'
    },

    // after
    bar() {
    return 'bar'
    }
    }

  • proto

    let o = {
    proto: new Foo()
    }

  • 属性名动态计算

    let arr = [1, 2, 3]
    let outArr = arr.map(n => {
    return {
    [ n ]: n,
    [ ${n}^2 ]: Math.pow(n, 2)
    }
    })
    console.dir(outArr) //=>
    [
    { '1': 1, '1^2': 1 },
    { '2': 2, '2^2': 4 },
    { '3': 3, '3^2': 9 }
    ]

  • 同名方法属性省略

    // module.js
    export default {
    someMethod
    }

    function someMethod() {
    // ...
    }

    // app.js
    import Module from './module'

    Module.someMethod()

const

let

产生块级作用域

for (let i = 0; i < buttons.length; i++) {
// ...
}

for-of循环

  • ES5中的循环(不能响应break,continue,return)

    myArray.forEach(function (value) {
    console.log(value);
    });

  • for-in(遍历属性)

  • 属性遍历

    for (var key of Object.keys(someObject)) {
    console.log(key + ": " + someObject[key]);
    }

  • for-of(为各种集合遍历数据如数组,可以响应break,continue,return,不只可以遍历数组)

    //遍历数组
    for (var value of myArray) {
    console.log(value);
    }
    //遍历字串
    for (var chr of "") {
    alert(chr);
    }
    //遍历set对象
    var uniqueWords = new Set(words);
    for (var word of uniqueWords) {
    console.log(word);
    }
    //遍历并解构map对象(map对象是键值对)
    for (var [key, value] of phoneBookMap) {
    console.log(key + "'s phone number is: " + value);
    }

  • 迭代器(实现迭代器方法就可以对对象使用for-of)

    // 使jQuery支持for-of
    jQuery.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

    for-of循环时会调用集合的[Symbol.iterator](),返回新的迭代器对象

    迭代器对象.next(),next()被反复调用

    var zeroesForeverIterator = {
    [Symbol.iterator]: function () {
    return this;
    },
    next: function () {
    return {done: false, value: 0};//无限循环,只返回0
    },
    return:function(){...}

    };

    迭代器对象.return(),过早退出会触发return(),异常,break,return会触发过早退出

    for-of执行过程:

    var $iterator = ITERABLESymbol.iterator;
    var $result = $iterator.next();
    while (!$result.done) {
    VAR = $result.value;
    一些语句
    $result = $iterator.next();
    }

生成器 Generators

生成器在执行过程中遇到yield时会暂停执行(生成器的堆栈结构包括本地变量,参数,临时值,当前执行位置会被移出堆栈,生成器对象会保留对这个堆栈的引用),在调用next()时重新激活堆栈结构并继续执行
yield不是退出而是切出

//定义生成器
function* quips(name) {
yield "你好 " + name + "!";
yield "希望你能喜欢这篇介绍ES6的译文";
if (name.startsWith("X")) {
yield "你的名字 " + name + " 首字母是X,这很酷!";
}
yield "我们下次再见!";
}
//执行
> var iter = quips("jorendorff");
[object Generator]
> iter.next()
{ value: "你好 jorendorff!", done: false }
> iter.next()
{ value: "希望你能喜欢这篇介绍ES6的译文", done: false }
> iter.next()
{ value: "我们下次再见!", done: false }
> iter.next()

生成器就是迭代器,生成器内建next()和[Symbol.iterator]()方法的实现,可以构建出永无止境的序列的生成器。

//传统迭代器的构建
class RangeIterator {
constructor(start, stop) {
this.value = start;
this.stop = stop;
}

Symbol.iterator { return this; }

next() {
var value = this.value;
if (value < this.stop) {
this.value++;
return {done: false, value: value};
} else {
return {done: true, value: undefined};
}
}
}

// 返回一个新的迭代器,可以从start到stop计数。
function range(start, stop) {
return new RangeIterator(start, stop);
}

//用生成器来构建迭代器
function* range(start, stop) {
for (var i = start; i < stop; i++)
yield i;
}

//生成器构建filter
function* filter(test, iterable) {
for (var item of iterable) {
if (test(item))
yield item;
}
}

//生成器用于异步
// 制造一些噪音的异步代码。
// 返回一个Promise对象
// 当我们制造完噪音的时候会变为resolved
function makeNoise_async() {
return Q.async(function* () {
yield shake_async();
yield rattle_async();
yield roll_async();
});
}

template strings

用``代替'',支持多行

function authorize(user, action) {
if (!user.hasPrivilege(action)) {
throw new Error(
用户 ${user.name} 未被授权执行 ${action} 操作。);// ${action}模板占位符
}
}

标签模板(tagged templates)

var message =SaferHTML<p>${bonk.sender} 向你示好。</p>;
//等同于
var message =SaferHTML(templateData, bonk.sender);
function SaferHTML(templateData) {//templateData Object.freeze(["

", " has sent you a bonk.

"] 不可变数组
var s = templateData[0];
for (var i = 1; i < arguments.length; i++) {
var arg = String(arguments[i]);

// 转义占位符中的特殊字符。
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/</g, ">");

// 不转义模板中的特殊字符。
s += templateData[i];
}
return s;
}

// 基于纯粹虚构的模板语言
// ES6标签模板。
var libraryHtml = hashTemplate <ul> #for book in ${myBooks} <li><i>#{book.title}</i> by #{book.author}</li> #end </ul> ;

不定参数,默认参数

  • 不定参数

    //传统方法
    function containsAll(haystack) {
    for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
    return false;
    }
    }
    return true;
    }
    //ES6实现方法
    //...needles为不定参数,必须在最后一位,参数传入时会赋一个数组,类似["b", "nan"],没有参数时[]
    function containsAll(haystack, ...needles) {
    for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
    return false;
    }
    }
    return true;
    }
    //调用
    containsAll("banana", "b", "nan")

  • 默认参数

    //参数自左向右求值,可以使用赋好值的其他参数
    function animalSentenceFancy(animals2="tigers",animals3=(animals2 == "bears") ? "sealions" : "bears")
    {
    return Lions and ${animals2} and ${animals3}! Oh my!;
    }

    animalSentenceFancy("bears") //“Lions and bears and sealions. Oh my!”

    //undefined相当于不传值
    animalSentence(undefined, "unicorns") //“Lions and tigers and unicorns! Oh my!

解构Destrucuring

  • 数组的结构([ variable1, variable2, ..., variableN ] = array;)

    var first = someArray[0];
    var second = someArray[1];
    var third = someArray[2];
    //解构
    var [first, second, third] = someArray;
    //嵌套结构
    var [foo, [[bar], baz]] = [1, [[2], 3]];
    //跳过其他元素
    var [,,third] = ["foo", "bar", "baz"];
    //不定参数结构
    var [head, ...tail] = [1, 2, 3, 4];
    console.log(tail);
    // [2, 3, 4]

    // undefined
    var [missing] = [];
    console.log(missing);

    function* fibs() {
    var a = 0;
    var b = 1;
    while (true) {
    yield a;
    [a, b] = [b, a + b];
    }
    }
    var [first, second, third, fourth, fifth, sixth] = fibs();
    console.log(sixth);
    // 5

  • 对象的解构

    var robotA = { name: "Bender" };
    var robotB = { name: "Flexo" };
    var { name: nameA } = robotA;
    var { name: nameB } = robotB;
    console.log(nameA);
    // "Bender"
    console.log(nameB);
    // "Flexo"

    //属性名与变量名一致时
    var { foo, bar } = { foo: "lorem", bar: "ipsum" };
    console.log(foo);
    // "lorem"
    console.log(bar);
    // "ipsum"

    //嵌套解构
    var complicatedObj = {
    arrayProp: [
    "Zapp",
    { second: "Brannigan" }
    ]
    };
    var { arrayProp: [first, { second }] } = complicatedObj;
    console.log(first);
    // "Zapp"
    console.log(second);
    // "Brannigan"

  • 解构的默认值

    var [missing = true] = [];
    console.log(missing);
    // true
    var { message: msg = "Something went wrong" } = {};
    console.log(msg);
    // "Something went wrong"
    var { x = 3 } = {};
    console.log(x);
    // 3

  • 解构用法

    //作为参数
    function removeBreakpoint({ url, line, column }) {
    // ...
    }

    //用于迭代
    var map = new Map();
    map.set(window, "the global");
    map.set(document, "the document");
    for (var [key, value] of map) {
    console.log(key + " is " + value);
    }
    // "[object Window] is the global"
    // "[object HTMLDocument] is the document"

    for (var [,value] of map) {
    // ...
    }

    //多值返回
    function returnMultipleValues() {
    return {
    foo: 1,
    bar: 2
    };
    }
    var { foo, bar } = returnMultipleValues();

Arrow Functions(lambda表达式)

在HTML中-->之前的字符是注释的一部分,而在JS中-->之后的部分才是注释(行首时会注释单行,行中时是趋向于运算符)
lambda中没有arguments

// ES5
var total = values.reduce(function (a, b) {
return a + b;
}, 0);
// ES6
var total = values.reduce((a, b) => a + b, 0);

// ES6
$("#confetti-btn").click(event => {
playTrumpet();
fireConfettiCannon();
});

var chewToys = puppies.map(puppy => {}); // 这样写会报Bug!
var chewToys = puppies.map(puppy => ({})); //

puppy => {}//返回undefined,大括号代表方法体

this

{
...
addAll: function addAll(pieces) {
var self = this;//this指向调用者,方法是调用者的一个属性
_.each(pieces, function (piece) {//内层函数里,this会是window或undefined,只能通过以下方法传递this
self.add(piece);//把调用者传给内层函数或.bind(this)
});
},
...
}

// ES6
{
...
addAll: function addAll(pieces) {
_.each(pieces, piece => this.add(piece));//lambda中的this可以继承外部函数中的this
},
...
}

Symbols

js中的6种原始类型undefined,null,boolean,number,string,object
symbols是第7种类型,可以用做属性键避免冲突,它的值与其他任何值都不相等,不能被类似obj.name的点号法访问,被创建后不可改变,当前作用域

var mySymbol = Symbol();
obj[mySymbol] = "ok!"; // 保证不会冲突
console.log(obj[mySymbol]); // ok!

// 创建一个独一无二的symbol
var isMoving = Symbol("isMoving");
...
if (element[isMoving]) {
smoothAnimations(element);
}
element[isMoving] = true;

symbols属性的操作

//属性是否存在
if (isMoving in element)
//删除属性
delete element[isMoving]

//会跳过symbols属性
Object.getOwnPropertyNames(obj)
Object.keys(obj)

//得到symbols属性
Object.getOwnPropertySymbols(obj)

//不能被隐式转换为string,必须显示转换
String(sym)
sym.toString()

创建symbols

//每次返回新的symbol
Symbol()
//共享symbol
Symbol.for(string)
//Symbol.iterator
myArray[Symbol.iterator]

转译器Babel,Broccoli

数据结构

set(不包含相同元素,无索引支持,通过数组构建set可以去重)

let s = new Set()
s.add('hello').add('world').add('hello')
console.log(s.size) //=> 2
console.log(s.has('hello')) //=> true

> // 检查"zythum"是不是一个单词
> arrayOfWords.indexOf("zythum") !== -1 // 慢
true
> setOfWords.has("zythum") // 快
true

new Set:创建一个新的、空的Set。
new Set(iterable):从任何可遍历数据中提取元素,构造出一个新的集合。
set.size:获取集合的大小,即其中元素的个数。
set.has(value):判定集合中是否含有指定元素,返回一个布尔值。
set.add(value):添加元素。如果与已有重复,则不产生效果。
set.delete(value):删除元素。如果并不存在,则不产生效果。.add()和.delete()都会返回集合自身,所以我们可以用链式语法。
setSymbol.iterator:返回一个新的遍历整个集合的迭代器。一般这个方法不会被直接调用,因为实际上就是它使集合能够被遍历,也就是说,我们可以直接写for (v of set) {...}等等。
set.forEach(f):直接用代码来解释好了,它就像是for (let value of set) { f(value, value, set); }的简写,类似于数组的.forEach()方法。
set.clear():清空集合。
set.keys()、set.values()和set.entries()返回各种迭代器,它们是为了兼容Map而提供的,所以我们待会儿再来看。

WeakSet

只能加入对象,如果对象的其他引用已经删除,则对象会从WeakSet中删除

let weaks = new WeakSet()
weaks.add("hello") //=> Error
weaks.add(3.1415) //=> Error

let foo = new String("bar")
let pi = new Number(3.1415)
weaks.add(foo)
weaks.add(pi)
weaks.has(foo) //=> true
foo = null
weaks.has(foo) //=> false

map

  • 避免与内置方法冲突

  • 数据不会作为属性暴露出来,obj.key,obj[key]不能再访问数据了,可以用map.get(key)访问数据

  • 对象可以作为属性

    new Map:返回一个新的、空的Map。
    new Map(pairs):根据所含元素形如[key, value]的数组pairs来创建一个新的Map。这里提供的pairs可以是一个已有的Map 对象,可以是一个由二元数组组成的数组,也可以是逐个生成二元数组的一个生成器,等等。
    map.size:返回Map中项目的个数。
    map.has(key):测试一个键名是否存在,类似key in obj。
    map.get(key):返回一个键名对应的值,若键名不存在则返回undefined,类似obj[key]。
    map.set(key, value):添加一对新的键值对,如果键名已存在就覆盖。
    map.delete(key):按键名删除一项,类似delete obj[key]。
    map.clear():清空Map。
    mapSymbol.iterator:返回遍历所有项的迭代器,每项用一个键和值组成的二元数组表示。
    map.forEach(f) 类似for (let [key, value] of map) { f(value, key, map); }。这里诡异的参数顺序,和Set中一样,是对应着Array.prototype.forEach()。
    map.keys():返回遍历所有键的迭代器。
    map.values():返回遍历所有值的迭代器。
    map.entries():返回遍历所有项的迭代器,就像mapSymbol.iterator。实际上,它们就是同一个方法,不同名字。

WeakMap

会检查key,value只有其一的引用被删除,就会从WeakMap中删除

WeakMap,WeakSet(方便垃圾收集)

//set是强引用,element作为key,如果element被从dom中移除了,无法回收他的内存,除非在set中也删除
//WeakSet并不对其中对象保持强引用。当WeakSet中的一个对象被回收时,它会简单地被从WeakSet中移除
if (movingSet.has(element)) {
smoothAnimations(element);
}
movingSet.add(element);

WeakMap只支持new、has、get、set 和delete。
WeakSet只支持new、has、add和delete。
WeakSet的值和WeakMap的键必须是对象。

Class

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

isAdult() {
return this.age >= 18
}
}

let me = new Person('iwillwen', 'man', 19)
console.log(me.isAdult()) //=> true

继承

class Animal {
yell() {
console.log('yell')
}
}

class Person extends Animal {
constructor(name, gender, age) {
super() // must call super before using this if this class has a superclass

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

isAdult() {
return this.age >= 18
}
}

class Man extends Person {
constructor(name, age) {
super(name, 'man', age)
}
}

let me = new Man('iwillwen', 19)
console.log(me.isAdult()) //=> true
me.yell()

静态方法

class Man {
// ...

static isMan(obj) {
return obj instanceof Man
}
}

let me = new Man()
console.log(Man.isMan(me)) //=> true

模块

全局引用

mport name from 'module-name'
import * as name from 'module-name'

局部引用

import { A, B, C } from 'module-name'

A()
B()
C()

暴露接口

// module.js
export function method() { /* ... */ }

// main.js
import M from './module'
M.method()

//覆盖暴露
// module.js
export default {
method1,
method2
}

// main.js
import M from './module'
M.method1()

Promise

function fetchData() {
return new Promise((resolve, reject) => {
api.call('fetch_data', (err, data) => {
if (err) return reject(err)

resolve(data)
})
})
}

fetchData()
.then(data => {
// ...

return storeInFileSystem(data)
})
.then(data => {
return renderUIAnimated(data)
})
.catch(err => console.error(err))

Proxy

不修改目标的前提下,拦截逻辑进行处理

let apiProxy = new Proxy(api, {
get(receiver, name) {
return (function(...args) {
min.sadd(log:${name}, args)
return receiver[name].apply(receiver, args)
}).bind(receiver)
}
})

api.getComments(artical.id)
.then(comments => {
// ...
})

深入浅出ES6
给 JavaScript 初心者的 ES2015 实战

posted @ 2015-09-30 10:49  fannet  阅读(418)  评论(0)    收藏  举报