ES6新特性简介
环境安装
npm install -g babel
npm install -g babel-node //提供基于node的REPL环境
//创建 .babelrc 文件
{"presets": ["es2015"]}
npm install babel-presets-es2015
箭头函数和词法this
箭头函数的用法类似phython
, coffeeScript
和 java8
//expression func body, (仅有1参数 括号可省略)
var odds = evens.map(v => v+1);
var nums = evens.map((v,i) => v + i);
//statement func body
nums.forEach( v => {
if(v % 5 === 0){
fives.push(v);
}
});
//lexical this
var sindy = {
name: 'Sindy',
friends: ['nami', 'robin'],
printFriends() {
//sindy.printFriends() this指向sindy,
//forEach迭代函数内部this,跟它定义的上下文this一致
this.friends.forEach(f=>{
console.log(this.name + ' knows ' + f);
});
}
};
类和继承
class
和 extend
是一种语法糖,也是基于原型继承实现的。class
支持 super calls
, 实例化,静态方法和构造函数。
class关键字 声明类
//class声明类 内部直接是属性和方法 不用,分隔。 constructor
class Person{
constructor(name, age){
this.name = name;//实例属性
this.age = age;
}
sayhi(name){//原型对象的方法
console.log(this.name+' say hello to ' + name);
}
static like(){//静态方法
console.log('i want to be freedom king');
}
}
extends关键字 声明继承
//继承关键字 extends
class Zoro extends Person{
constructor(fav){
super('zoro', 18); //constructor中, super引用父类的构造函数
this.fav = 'keep going';
// console.log(super); //error 不能直接打印super
console.log(super('cici',9),'<--c');
}
sayhi(){
// console.log(super); //error 不能直接打印super
console.log(super.sayhi(),'<--m'); //原型对象的方法中, super引用父类的原型对象
super.sayhi();//调用父类原型对象的方法
}
}
增强的对象字面量
书写对象字面量更方便简洁。 如:foo:foo
的简写, 函数定义简写, 动态属性名。
var obj = {
__proto__: theProtoObj, //设置原型对象
['__proto__']: somethingElse, //['__proto__']表示计算的属性名,不会认为是设置原型对象, 有时也可避免提早报同名属性的错误
handler, // hanlder: handler 的简写
toString(){//类似定义类 命名函数表达式的名称作为key
//super calls
return 'd' + super.toString(); //super 应该指向 theProtoObj
},
['prop_'+(()=>23)]: 23 //[expression] 中括号表示内部为属性名的计算表达式,可实现动态属性名
}
__proto__
属性在node下都支持,但在浏览器环境不一定都支持, chrome是支持的。
模板字符串
模板字符串跟php双引号字符串类似 "hello ,$name"
,字符串中可以解析变量和语句, 对于构造字符串是很方便的。
//单行
`this is an alone night`
//多行
`In ES5 this is
not legal`
//变量插值
var name = 'idle', time='today';
var greeting = `hello ${name}, how are you ${time}`;
//不转义
String.raw`in es5 "\n" is a line-feed`
解构
参数解构 对象解构 数组解构, 解构是一种十分方便的语法特性. 当结构不对应解析失败时,会对应的返回undefined,不报错.
//解构赋值
var [a, b] = [1,2]; // a===1, b===2
var {name, age} = getPerson();
//参数解构
function hello({name: x}){
console.log('hello, ', x);
}
hello({name: 'alice'});
//解构失败
var [a] = []; // a===undefined
//提供解构失败时的默认值
var [a=1] = []; //a===1
//参数解构失败的默认值
function r({x,y,w=10,h=20}){
return x+y+w+h;
}
r({x:1, y:2});
//参数默认值
function f(a, b=10){
return a+b;
}
f(5);
//rest arguments
function f(x,...y){//剩余形参
// y is an array
return x * y.length
}
f(3, 'hello', true);//6
function f(x,y,z){
return x+y+z;
}
f(...[2,3,4]); //=>9 剩余实参
块级作用域
let
和 const
声明的变量和常量都是属于块级作用域的.
function f(){
let x;
{
const x = 'sindy'; //ok 因为块级作用域
x = 'foo'; //error 因为x是常量
}
x = 'bar'; //在let 之后赋值,没问题
let x = 'inner'; //error 重复声明
}
迭代对象(iterator) 和 for .. of ..
迭代对象允许自定义迭代方式,如:
let fibonacci = {
[Symbol.iterator]() {
let pre=0, cur=1;
return {//返回包含next方法的迭代对象(iterator)
next(){
[pre, cur] = [cur, pre+cur];
return {done: false, value: cur}; //iteratorResult
}
}
}
};
for(var n of fibonacci){
if(n>100){//若无终止条件会一直迭代下去 n应该代表的是每次迭代的结果
break;
}
console.log(n);
}
//typescript风格的iterator接口定义
interface IteratorResult{
done: boolean,
value: any
}
interface Iterator {
next(): IteratorResult //包含next方法,且next()返回IteratorResult类型结果
}
interface Iterable {
[Symbol.iterator](): Iterator // fibonacci() 执行后返回Iterator
}
生成器generators
function*
和 yield
, function*
声明的函数返回一个generator实例. generator是iterator的子类型,它包含自己的throw
和next
generator可以实现await风格的异步编程
//generator版的fibonacci
var fibonacci = {
[Symbol.iterator]: function*() {//function*声明
var pre=0, cur=1;
for(;;){//不会终止的循环?
var temp = pre;
pre = cur;
cur += pre;
yield cur;//generator实例每次执行都从yield的地方重新开始?
}
}
};
for(var n of fibonacci){
if(n > 100){
break;
}
console.log(n);
}
//typescript风格的generator接口定义
interface generator extends iterator {
next(value?: any): IteratorResult; //next方法可带参数, yield返回参数给next?
throw(exception: any);
}
注意 iterator and generator 目前需要polyfill才能使用, 新版的chrome已支持.
unicode的完全支持
// same as ES5.1
"?".length == 2
// new RegExp behaviour, opt-in ‘u’
"?".match(/./u)[0].length == 2
// new form
"\u{20BB7}" == "?" == "\uD842\uDFB7"
// new String ops
"?".codePointAt(0) == 0x20BB7
// for-of iterates code points
for(var c of "?") {
console.log(c);
}
模块(modules)
ES6有不同于amd
和 cmd
的模块风格
//>lib/math.js
export function sum(x,y){
return x + y;
}
export var fnum = 3.122323;
//>app.js
import * as math from 'lib/math';
console.log(math.sum, math.fnum);
//>other.js
import {fnum, sum} from 'lib/math'; //对象解构赋值
console.log(fnum, sum);
一些额外的特性 export default
和 export *
//>lib/otherMath.js
export * from 'lib/math'; //导出math.js的接口
export var e = 2.323;
export default function(x){
return Math.exp(x);
}
//>app.js
import exp, {sum , e} from 'lib/otherMath';
模块导出 export
var name = 'sindy';
var age = 20;
//相当于node module.exports = {name:name, age:age};
export {name, age};
//相当于module.exports.default = function getName(){..}
export default function getName(){
return name;
}
模块导入 import
//import m from './modA'; m === modA.export.default
//import {name, age} from './modA' modA.exports 析构
import getName, {name, age} from './module-e.es';
console.log(name, age);
console.log(getName());
Map , Set, WeakMap, WeakSet
//Sets
var s = new Set();
s.add('hello').add('goodbye').add('hello');//已有则不再加入
s.size === 2; //true
//Maps
var m = new Map();
m.set('hello', 'good');
m.set(s, 23);
m.get(s) === 23;
//WeakMap
var wm = new WeakMap();
wm.set(s, {extra:24});
vm.size === undefined;
//WeakSet
var ws = new WeakSet();
ws.add({data:12});
proxies
拦截或代理对象的属性读写,函数的调用。
//proxy a normal object
var target = {};//被代理的对象
var handler = {//代理哪些方法
get: function(reciever, name){//get代理对属性的访问
return `hello, ${name}`;
}
};
var p = new Proxy(target, handler);
p.world === 'hello, world';
//proxy a function object
var target = function(){ console.log('i am the target'); };
var handler = {
apply: function(reciever,...args){//代理 target()
console.log('i am the proxy');
}
};
//代理的类型
var handler = {
//target.prop
get: ...,
//target.prop = val
set: ...,
//prop in target
has: ...,
//delete target.prop
deleteProperty: ...,
//target(args)
apply: ...,
//new target(args)
constructor: ...,
//Object.getOwnPropertyDescriptor(target, prop)
getOwnPropertyDescriptor: ...,
//Object.defineProperty(target, prop, descriptor)
defineProperty: ...,
//Object.getPrototypeOf(target), target.__proto__
//obj.isPrototypeOf(target), obj2 instanceof target
getPrototypeOf: ...,
//Object.setPrototypeOf(target, proto)
setPrototypeOf: ...,
//for(var i in target)
enumerate: ...,
//Object.keys(target)
ownKeys: ...,
//Object.preventExtensions(target)
preventExtensions: ...,
//Object.isExtensible(target)
isExtensible: ...
}
标识符 symbol
(function(){
//module scope symbol
var key = Symbol('key');
function MyClass(privateData){
this[key] = privateData;
}
MyClass.prototype = {
dostuff: function(){
...this[key]..
}
};
typeof key === 'symbol';
})();
var c = new MyClass();
c['key'] === undefined;
内置的子类
Array
, Date
,Element
等成为内置的子类。
class MyArray extends Array{
constructor(...args){
super(...args);
}
}
var arr = new MyArray();
arr[1] = 12;
arr.length === 2;
Math + Number + String + Object API扩展
Number.isInterger(Ifinity); //false
Number.isNaN('NaN'); //false
Math.hypot(3,4); //5
'abcde'.includes('abc');
'abc'.repeat(2);
Array.from(document.querySelectAll('h2')); //return a real array
Array.of(1,2,3); => [1,2,3] 枚举数组元素的形式 创建数据, 同 new Array(1,2,3); 但没有仅有1各参数时的歧义
[0,0,0].fill(7,1); //从index==1开始填充7
[1,2,3].findIndex(x=>x==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'
var alice = {name: 'Alice'};
Object.assign(alice, {age: 18}); //类似extend
二进制和八进制字面量
0b111110111 === 503
0o767 === 503
Promises
Promise
是一个异步编程的库,存在于很多其他的JS库中
function timeout(duration = 0){
return new Promise((resolve, reject) => {//返回稍后将被resolve的promise对象
setTimeout(resolve, duration);//定时resolve这个新new的promise
});
}
var p = timeout(1000).then(()=>{//promise链
return timeout(2000);
}).then(()=>{
throw new Error('test');
}).catch(err=>{
return Promise.all([timeout(100), timeout(200)]);
});
反射API(Reflect API)
var o = {a: 1};
Object.defineProperty(o, 'b', {value:2});
o[Symbol('c')] = 3;
Reflect.ownKeys(o); //['a','b',Symbol(c)]
function C(a,b){
return this.c = a + b;
}
var instance = Reflect.construct(C, [10,12]);
instance.c === 22;
尾调用 tail calls
防止stack overflow
function factorial(n, acc=1){//阶乘计算
'use strict';
if(n <= 1){ return acc; }
return factorail(n-1, n*acc);
}
factorail(10000); //尾调用优化后不会 stack overflow