ES6简单使用介绍

ES6 正式发布也久矣,2015年就发布了,所以赶紧用起来吧。相对来说,如果你会了TypeScript,那ES6也基本不是事儿了吧。

let和const

1、通用特性:声明不能提升,必须先声明后使用;只在声明所在的块级作用域内有效;不能重复声明。否则均会报错。

console.log(test);//test is not defined
let test;
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);//i is not defined
let i=1;
let i=2;
console.log(it);//Identifier 'i' has already been declared

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}

2、let 和块级作用域

ES6通过let和{}来实现块级作用域,解决了for循环、if语句泄露变量到全局,内层变量不会覆盖外层变量。

function f1() {
let n = 5;
if (true) {
let n = 10;
}
console.log(n); //5
}

注意:ES6虽然允许在块级作用域内声明函数,但是会和实现ES5的浏览器相冲突导致出错,所以不要在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

3、const:声明一个只读的常量。一旦声明,常量的值就不能改变,所以必须声明后立即赋值,否则报错。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

箭头函数

箭头函数相当于匿名函数,如果只包含一个表达式则可以省略{}和return语句,如果没有参数或者有多个参数则要用()括起来。

x => x*x
() => 3.14
x => {
return x*x
}
(a,b) => {
return a+b
}

箭头函数中的this

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,即箭头函数可以让this指向固定化。
  • 不可以当作构造函数,也就是说,不可以使用new命令。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
  • 用call()调用箭头函数时第一个参数会被忽略
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });// id: 42

Generator

生成器函数,类似一个状态机,通过next()会遍历每个yield后面的值,每次返回value和done的结果,一直遍历到最后得到return返回值,最后的状态才会返回done:true。

function* show(){
yield 'hello';
yield 'world';
return 'ok'
}
show();//此时不会有任何反应
console.log(show().next());//得到{value:'hello',done:false}
console.log(show().next());//得到{value:'world',done:false}
console.log(show().next());//得到{value:'ok',done:true}

yield语句本身没有返回值,或者返回undefined
next()也可以有参数,但是参数的作用是作为上一个yield的返回值
可以用for…of循环来遍历Generator函数

function* show(){
yield 'hello';
yield 'world';
return 'ok'
}
for(let n of show()){
console.log(n);//hello,world,没有OK
}

async

async是Generator函数的语法糖,配合await实现异步操作,async关键字表示后面的函数里面有异步操作,await表示紧跟在后面的表达式需要等待结果。async返回一个Promise对象,可以用then添加回调函数。async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);//会在50毫秒之后得到hello world

class

类:

class Person{
constructor(name,age){
this.name=name;
this.age=age;
}
showName(){
console.log(this.name)
}
showAge(){
console.log(this.age)
}
}
let p1=new Person('Apple',10);
let p2=new Person('Orange',20);
p1.showName();//Apple
p1.showName ==p2.showName;//true
p1.constructor==Person;//true

继承:extends

class Worker extends Person{
//子类继承父类
}
  • 在构造函数内部实现继承父类的属性,并添加自己的方法,需要super()来实现
//接上例
class Worker extends Person{
//子类继承父类
constructor(name,age,job){
super(name,age);//使用父类的构造函数
this.job=job;//添加自己的属性
}
showJob(){
console.log(this.job);
}
}
let w1=new Worker('iOS',10,'打杂的');
w1.showJob();//打杂的
w1.showName();//iOS 不影响父类

###补充

1、ES6新增函数...rest参数,可以获取指定参数之外的其他所有参数,返回一个数组。

function fn(a,b,...rest){//注意...rest一定要在所有参数的最后面
console.log(a);//1
console.log(b);//2
console.log(rest);//[3,4,5]
}
fn(1,2,3,4,5);

2、解构赋值:按照一定模式从数组或者对象中提取值,并对变量进行赋值。解构时等号右边必须是可以遍历的对象。如果等号左右结构不一致,则会选取对应的位置进行解构赋值,不对应的返回undefined。

(1)数组解构:按照对应位置进行解构赋值,多个变量要用[]包围起来

let a=1;
let b=2;
let c=3;
//可以写成:
let [a, b, c] = [1, 2, 3];

(2)对象解构:从等号右侧取同名属性的值,

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
//如果先声明变量再赋值,需要用()包围起来,否则会被JS引擎当做代码块
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj // {prop:123}
arr // [true]

(3)解构的应用

  • 交换变量的值:
let x = 1;
let y = 2;
[x, y] = [y, x];
  • 提取JSON数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

3、Proxy

可以理解成通过Proxy来对外部的访问进行过滤和改写。它有两个参数,第一个是目标对象,第二个是方法(get/set)

举个例子:

//原来我们这样获取对象的属性值:
var person={
getMsg:function(){
console.log(this.name+' '+this.age)
}
};

4、Set 不允许重复元素的数组,通过 new Set() 来实现

let s=new Set([1,2,3,3]);//得到[1,2,3]
s.add(4);//得到[1,2,3,4]
s.delete(2);//得到[1,3,4]
s.has(5);//判断是否含有5,返回false
s.clear();//清空数组元素
//去除数组重复元素:
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];
// [3, 5, 2]

总结:ES6有的东西确实带来了很大方便,但是有的使用门槛较高,我这里只是简单的用法,复杂的还需要继续研究一下,我觉得可以直接学习TypeScript,再回过来看ES6的东西会感觉简单许多。

参考:阮一峰 ECMAScript6 入门