语法
箭头函数、this
ES6中可以使用 => 作为函数表达形式,极简风格,参数+ => +函数体。
// 1.1单行 无参数
var foo = function(){return 1}
//等价于
let foo = () => 1
// 1.1单行 有参数
var foo = function(x){return x}
//等价于
let foo = (x) => x
// 2.1多行
function add(a,b){
console.log(a+b)
return a+b
}
// 等价于
let add = (a,b)=>{
console.log(a+b)
return a+b
}
// test
let nums = [1,2,3,5,10]
let fives = []
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v)
});
console.log(fives) //[5,10]
箭头函数中的 this 指的不是window,是对象本身。
function aa(){
this.bb = 1;
setTimeout(() => {
this.bb++; //this指向aa
console.log(this.bb);
},500);
}
aa(); //2
let、const
ES6 推荐在函数中使用 let 定义变量
const 用来声明一个常量,但也并非一成不变的
- let 和 const 只在最近的一个块中(花括号中)有效
var a = 1;
{
let a = 2;
console.log(a); //2
}
console.log(a); //1
const A = [1,2];
A.push = 3;
console.log(A); //[1,2,3]
A = 10; //Error
Classes
JavaScript语言的传统方法是通过构造函数,定义并生成新对象
Class内部只有静态方法,没有静态属性,但可以用另外方式解决
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
//这种写法跟传统的面向对象语言(比如C++和Java)差异很大,很容易让新学习这门语言的程序员感到困惑
- ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
//上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。
//也就是说,ES5的构造函数Point,对应ES6的Point类的构造方法
test
class Animal {
constructor(){
console.log('我是一个动物');
}
}
class Person extends Animal {
constructor(){
super();
console.log('我是一个程序员');
}
}
let aa = new Person();
//我是一个动物
//我是一个程序员
解构
解构赋值是ES6中推出的一种高效、简洁的赋值方法
没啥说的,直接上代码:
//通常情况下
var first = someArray[0];
var second = someArray[1];
var third = someArray[2];
//解构赋值
let [first, second, third] = someArray; //比上面简洁多了吧
//还有下面例子
let [,,third] = [1,2,3];
console.log(third); //3
let [first,...last] = [1,2,3];
console.log(last); //[2,3]
//对象解构
let {name,age} = {name: "lisi", age: "20"};
console.log(name); //lisi
console.log(age); //20
let {ept} = {};
console.log(ept); //undefined
Rest + Spread
“…”
//Rest
function f(x, ...y) {
return x * y.length;
}
f(3, "hello", true) == 6
//Spread
function f(x, y, z) {
return x + y + z;
}
f(...[1,2,3]) == 6
对象于面量扩展
- 可以在对象字面量里面定义原型
- 定义方法可以不用function关键字
- 直接调用父类方法
//通过对象字面量创建对象
var human = {
breathe() {
console.log('breathing...');
}
};
var worker = {
__proto__: human, //设置此对象的原型为human,相当于继承human
company: 'freelancer',
work() {
console.log('working...');
}
};
human.breathe();//输出 ‘breathing...’
//调用继承来的breathe方法
worker.breathe();//输出 ‘breathing...’
模版字符串
ES6中提供了用反引号`来创建字符串,里面可包含${…}等
`This is a pretty little template string.`
`In ES5 this is
not legal.`
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
Iterators(迭代器)
ES6 中可以通过 Symbol.iterator
给对象设置默认的遍历器,直到状态为true退出。可以是数组,对象,Set,Map类型的。
var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
itr.next(); //{ value: 11, done: false }
itr.next(); //{ value: 12, done: false }
itr.next(); //{ value: 13, done: false }
itr.next(); //{ value: undefined, done: true }
// 循环输出,该循环速度快
for(;;){
let elem = itr.next()
if(elem.done){
break
}
console.log(elem.value)
}
Generators
Generators函数是ES6新增的一种异步编程方案。是一种新的语法结构,一个遍历器对象生成器,它内部可以封装多个状态,非常适合异步操作。
Generators函数语法和普通的function函数类似,但是有三个不同点:
- (1)function关键字和函数名称之间有一个星号(*)
- (2)函数体内可以使用yieId语句
- (3)函数调用后不会立即执行,返回的是一个遍历器对象
Run-Stop-Run…
// 1.
function *foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var it = foo( 5 );
console.log( it.next() ); // { value:6, done:false }
console.log( it.next( 12 ) ); // { value:8, done:false }
console.log( it.next( 13 ) ); // { value:42, done:true }
// 2.
// 一个Generators函数
function *yuanku(){
yieId "冤苦",
yieId "冤苦",
yieId "冤苦",
return "end"
}
// 函数内部使用yieId语句定义不同状态,return也可以定义一个状态,也就是说上面代码有四个状态
var y = yuanku() // 调用此函数,并不会立即执行它其中的代码,而是返回一个遍历器对象
console.log(y.next()) // 返回一个具有value和done属性的对象
console.log(y.next()) // youreturn,返回(value:end,done:true);如果没有return,返回(value:undefined,done:true)
// yieId语句
// 每一个yieId语句定义不同的状态,它也是一个代码执行暂停标识
//yieId语句不能在普通函数中使用,否则会报错
// 调用Generators函数可以返回一个遍历器对象,要想访问Generators函数中的每一个状态,需要使用遍历器对象调用next()方法
// 如果使用yieId语句作为其他语句的额一部分,那么必须使用小括号包裹,否则会报错。例如:
function *yuanku(){
//console.log("欢迎来到"+yieId"冤苦") // 报错
console.log("欢迎来到"+(yieId"冤苦"))// 正确
}
let y = yuanku()
console.log(y.next().value) // 先返回yieId
console.log(y.next().value) // 再返回return,yieId为undefined
generator能实现好多功能,如配合for…of使用,实现异步等等,我在这里就不多说了。
for…of && for…in
- for…of 遍历(数组)
let arr = [1,2,3];
for (let itr of arr) {
console.log(itr); //1 2 3
}
- for…in 遍历(对象中的属性)
let arr = [1,2,3];
arr.aa = 'bb';
for (let itr in arr) {
console.log(itr); //0 1 2 aa
}
Map + Set + WeakMap + WeakSet
Set 对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型
WeakSet是一种弱引用(垃圾自动回收,防止内存泄漏),只用于对象。同理WeakMap(键名只接受对象)
// 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;
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
Proxies
Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”
//定义被侦听的目标对象
var engineer = { name: 'Joe Sixpack', salary: 50 };
//定义处理程序
var interceptor = {
set: function (receiver, property, value) {
console.log(property, 'is changed to', value);
receiver[property] = value;
}
};
//创建代理以进行侦听
engineer = Proxy(engineer, interceptor);
//做一些改动来触发代理
engineer.salary = 60;
//控制台输出:salary is changed to 60
Symbols
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)
Symbol值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型
Symbol 是一种新的字符串数据类型,它的值是唯一的,不可变的。
- ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符.
1、类型
let s = Symbol();
typeof s
// "symbol"
- 上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是Symbol数据类型,而不是字符串之类的其他类型
- 注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型
2、 如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值
var s1 = Symbol('foo');
var s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
注意,Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。
3 、没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
4、有参数的情况
var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2 // false
上面代码中,s1和s2都是Symbol函数的返回值,而且参数相同,但是它们是不相等的
5、Symbol值不能与其他类型的值进行运算,会报错
var sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string
6、但是,Symbol值可以显式转为字符串。
var sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
8、另外,Symbol值也可以转为布尔值,但是不能转为数值。
var sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
- 如果要获取对象 symbol 属性,需要使用
Object.getOwnPropertySymbols(o)
Promises
ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者 rejected
Promises对象具有三种状态:Pending(等待)、Resolved(已完成)、Rejected(未完成)
Promises对象状态的改变只有两种可能:Pending转变为Resolved,或者Pending转变为Rejected
Promises是处理异步操作的一种模式,之前在很多三方库中有实现,比如jQuery的 deferred 对象。当你发起一个异步请求,并绑定了.when(), .done()等事件处理程序时,其实就是在应用promise模式
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
})
}
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("hmm");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
})
想要了解promise实际应用等,详见。
小结
总之,ES6还是有很多棒棒的语法,有利于精简代码,高效开发;只不过一些低级别浏览器不支持,可以用Babel等工具把ES6转化成ES5