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 = ITERABLE[Symbol.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()
{ value: undefined, done: true }
生成器就是迭代器,生成器内建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(["<p>", " has sent you a bonk.</p>"] 不可变数组
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 => {
// ...
})