*1. 变量、常量声明
{
var a = 'var';
let b = 'let';
const c = 'const';//常量
console.log(a + ',' + b);//1,2
}
console.log(a + ',' + b);//ReferenceError: b is not defined
//let增加了块级作用域,内外不同
*2. 解构赋值
//变量
let [, [, [c]]] = [1, [2, [3]]];//深层嵌套,单一也一样,逗号前也可用变量,同等情况赋值,var,const都可
console.log(c);//3
let [a, ...b] = [1, 2, 3];//"rest模式"
console.log(a+','+ b);//1, 2, 3
console.log(b);//[2, 3]
//对象
let robotA = { name: "Bender" };//对象名,属性,值
let { name: nameA } = robotA;//属性,变量名,对象名
console.log(nameA);// "Bender"
var { foo, bar } = { foo: "lorem", bar: "ipsum" };//对象名=属性,值
console.log(foo);// "lorem"
//注意
var {blowUp} = null;// TypeError: can't convert null to object
//使用对象赋值模式时,被解构的值必需能够转换成一个对象(object)。大多数的类型都可以转换为一个对象,但null和undefined却并不能被转换。
//默认值
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
*3. 箭头函数Arrow Function
// ES5
function total(a, b) {
let a = b;
return a + b;
};
// ES6
var total = (a, b) => {
let a = b;
return a + b
};//单个参数可省略括号;函数体只有return ...可省略大括号;去掉前缀就是匿名函数;返回一个对象必须({})小括号包对象
/*this in arrow function*/
//ES5
{
...
addAll: function(pieces) {
var self = this;//保存this
_.each(pieces, function (piece) {
self.add(piece);//使用外部this
});
},
...
}
// ES6的方法语法
{
...
addAll(pieces) {
_.each(pieces, piece => this.add(piece));//this继承了外围作用域的this值,不可改变
},
...
}
*4. 函数参数
//默认值default
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
//参数打包Rest
function f(x, ...y) {// y is an Array
return x * y.length;
}
f(3, "hello", true);//6
//数组展开Spread
function f(x, y, z) {
return x + y + z;
}
f(...[1,2,3]);// 6
*5. 字符串模块Template Strings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`// return "Hello Bob, how are you today?"
//大括号里也可以是函数fn(),取得函数返回值
*6. 迭代器Iterators、生成器Generator
对集合中的任意项进行处理是很常见的操作。JavaScript 提供了好几种方法来遍历一个集合,从简单的 for循环至 map()和filter() 。迭代器和生成器将迭代的概念纳入javascritp的核心语言中,并提供了一种自定义 for...of 循环体的机制 。
//迭代器
//在JavaScript 中迭代器是一个对象,提供 next() 方法,返回序列中的下一项。这个方法返回包含done和value两个属性的对象。for-in可代替,但是无序,for-of可代替
function makeIterator(array){//创建一个迭代器,如果是对象,可设置第二个参数表示是否迭代属性值。。。
var nextIndex = 0;
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
}
}
var it = makeIterator(['yo', 'ya']);//一旦初始化,next()方法可以用来依次访问对象中的键-值
console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true
//生成器:一个更好的方法来构建遍历器
//一个生成器其实是一种特殊类型的函数(这个函数作为一个为迭代器工作的工厂),一个函数如果它里面包含了一个或一个以上的yield表达式(yield关键字只能被包含在下面的代码快中才有用 <script type="application/javascript;version=1.7"> (或者更高版本).XUL脚本标记访问这些功能不需要这个特殊的块。),那么这个函数就成为一个生成器了。
function* (){};//生成器函数:一种可以从中退出并在之后重新进入的函数。生成器的环境(绑定的变量)会在每次执行后被保存,下次进入时可继续使用。
//当一个生成器函数被一个函数体调用时并不会马上执行;相反,它会返回一个generator-iterator对象。每次调用generator-iterator的next()方法将会执行这个函数体至下一个yield表达式并且返回一个结果。当函数执行完或者执行到一个return时抛出一个StopIteration exception异常。
function* simpleGenerator(){
yield "first";
yield "second";
yield "third";
for (var i = 0; i < 3; i++)
yield i;
}
var g = simpleGenerator();
print(g.next()); // prints "first"
print(g.next()); // prints "second"
print(g.next()); // prints "third"
print(g.next()); // prints 0
print(g.next()); // prints 1
print(g.next()); // prints 2
print(g.next()); // StopIteration is thrown
/*generator-iterator对象的send()方法可以用来修改生成器的内部状态。
传递一个值给send()将被视为最后一个yield表达式的结果(生成器暂停)。(个人观点:相当于重启生成器)
你必须在你使用send(参数)前通过调用next()来启动生成器。
*/
/*generator-iterator对象的close() 方法来强制生成器结束。结束一个生成器会产生如下影响:
所有生成器中有效的 finally 字句将会执行;
如果 finally 字句抛出了除 StopIteration 以外的任何异常,该异常将会被传递到 close() 方法的调用者;
生成器会终止
*/
*7. Class。有constructor、extends、super,但本质上是语法糖(对语言的功能并没有影响,但是更方便程序员使用)
class Artist {
constructor(name) {
this.name = name;
}
perform() {
return this.name + " performs ";
}
}
class Singer extends Artist {
constructor(name, song) {
super.constructor(name);
this.song = song;
}
perform() {
return super.perform() + "[" + this.song + "]";
}
}
let james = new Singer("Etta James", "At last");
james instanceof Artist; // true
james instanceof Singer; // true
james.perform(); // "Etta James performs [At last]"
*8. Modules
//ES6提供了如下几种导入方式:
// Default exports and named exports
import theDefault, { named1, named2 } from 'src/mylib';
import theDefault from 'src/mylib';
import { named1, named2 } from 'src/mylib';
// Renaming: import named1 as myNamed1
import { named1 as myNamed1, named2 } from 'src/mylib';
// Importing the module as an object (with one property per named export)
import * as mylib from 'src/mylib';
// Only load the module, don’t import anything
import 'src/mylib';
//如下几种导出方式:
//命名导出
export var myVar1 = ...;
export let myVar2 = ...;
export const MY_CONST = ...;
export function myFunc() {}
export function* myGeneratorFunc() {}
export class MyClass {}
// default 导出
export default 123;
export default function (x) {
return x
};
export default x => x;
export default class {
constructor(x, y) {
this.x = x;
this.y = y;
}
};
//也可以自己列出所有导出内容
const MY_CONST = ...;
function myFunc() {}
export { MY_CONST, myFunc };
//或者在导出的时候给他们改个名字
export { MY_CONST as THE_CONST, myFunc as theFunc };
//还可以导出从其他地方导入的模块
export * from 'src/other_module';
export { foo, bar } from 'src/other_module';
export { foo as myFoo, bar } from 'src/other_module';
*9. Map映射 + Set集合 + WeakMap弱映射 + WeakSet弱集合
// Sets,不易被回收
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
// Maps,不易被回收
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
//WeakMap,允许从内存中清除不再需要的被这些集合所引用的对象。
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets,允许从内存中清除不再需要的被这些集合所引用的对象。
var ws = new WeakSet();
ws.add({ data: 42 });//Because the added object has no other references, it will not be held in the set
*10. Math + Number + String + Array + Object APIs
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
Array.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[0, 0, 0].fill(7, 1) // [0,7,7]
[1, 2, 3].find(x => x == 3) // 3
[1, 2, 3].findIndex(x => x == 2) // 1
[1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2]
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"
Object.assign(Point, { origin: new Point(0,0) })
*11. 代理Proxies
使用代理(Proxy)监听对象的操作
//可监听的操作: get、set、has、deleteProperty、apply、construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible。
var target = {};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}!`;
}
};
var p = new Proxy(target, handler);
p.world === 'Hello, world!';
*12. Symbol
一种新的原始数据类型Symbol,表示独一无二的值
/*
*Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象
*Symbol值不能与其他类型的值进行运算
*Symbol值作为对象属性名时,不能用点运算符
*Symbol值作为属性名时,该属性还是公开属性,不是私有属性
**/
// 没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
// 有参数的情况
var s1 = Symbol("foo");
var s2 = Symbol("foo");
s1 === s2 // false
//作为属性
var a = {};
var name = Symbol();
a.name = 'lili';
a[name] = 'lucy';
console.log(a.name,a[name]); //lili,lucy
//Symbol.for(),首先在全局中搜索有没有以该参数作为名称的Symbol值,有就返回这个Symbol值,否则新建并返回一个以该字符串为名称的Symbol值。和原Symbol不同。
var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
s1 === s2 // true
//Symbol.keyFor()返回一个已登记的Symbol类型值的key。实质就是检测该Symbol是否已创建
var s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
var s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
*13. Promises
Promises是处理异步操作的对象,使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观(类似jQuery的$.Deferred())。
Promises三种状态:Fulfilled(成功);Rejected(失败);Pending(Promise 对象实例创建时候的初始状态)
//then、 catch
function helloWorld (ready) {
return new Promise(function (resolve, reject) {
if (ready) {
resolve("Hello World!");
} else {
reject("Good bye!");
}
});
}
helloWorld(true).then(function (message) {
alert(message);//resolve的内容
}, function (error) {
alert(error);//reject的内容
});
//then(onFulfilld, onRejected) 方法就是根据 Promise 对象的状态来确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)
//then(onFulfilld, onRejected) 可写成then(fn).catch(fn)相当于 then(fn).then(null, fn),catch(fn相当于)onRejected 函数的一个简写
helloWorld(true).then(function (message) {
return message;
}).then(function (message) {
return message + ' World';
}).then(function (message) {
return message + '!';
}).then(function (message) {
alert(message);
});
//上述例子通过链式调用的方式,按顺序打印出了相应的内容。then 可以使用链式调用的写法原因在于,每一次执行该方法时总是会返回一个 Promise 对象。另外,在 then onFulfilled 的函数当中的返回值,可以作为后续操作的参数
//Promises.all()、Promises.race()
//Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。
var p1 = new Promise(function (resolve) {
setTimeout(function () {
resolve("Hello");
}, 3000);
});
var p2 = new Promise(function (resolve) {
setTimeout(function () {
resolve("World");
}, 1000);
});
Promise.all([p1, p2]).then(function (result) {
console.log(result); // ["Hello", "World"]
});
//上面的例子模拟了传输两个数据需要不同的时长,虽然 p2 的速度比 p1 要快,但是 Promise.all 方法会按照数组里面的顺序将结果返回。
//使用场景:通常接口之间没有关联(例如不需要前一个接口的数据作为后一个接口的参数),这个时候 Promise.all 方法就可以派上用场了
//Promise.race,它同样接收一个数组,不同的是只要该数组中的 Promise 对象的状态发生变化(无论是 resolve 还是 reject)该方法都会返回。
参见:
浅谈JavaScript、ES5、ES6
ES6与ES5差别
【探秘ES6】系列专栏(六):解构赋值
深入浅出ES6(七):箭头函数 Arrow Functions
迭代器和生成器
ES6详解八:模块(Module)!
ES6入门之Symbol
谈谈 ES6 的 Promise 对象