类
ES6引入了class(类),让javaScript的面向对象课程变得更加简单和易于理解。
class Animal{
constructor(name ,color){
this.name = name;
this.color = color;
}
toString(){
console.log('name:'+this.name+',color:'+this.color);
}
}
var animal = new Animal('dog','white');
animal.toString();
class Cat extends Animal{
constructor(action){
//子类必须要在constructor中指定super函数
//如果没有置顶constructor,默认带super函数的constructor会被添加
super('cat','white');
this.action = action;
}
toString() {
console.log(super.toString());
}
}
var cat = new Cat('catch');
//实例cat 是 Cat和 Animal的实例和 Es5完全一致
console.log(cat instanceof Cat);
console.log(cat instanceof Animal);
模块化(Module)
ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由export和import组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过export来规定模块对外暴露的接口,通过import来引入其他模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
导出(export)
ES6允许在一个模块中使用export来导出多个变量和函数。
导出变量
export var name = 'Rainbow';
//export 不仅支持变量的导出,也支持常量的导出
export const sqrt = Math.sqrt;
ES6将一个文件视为一个模块,上面的模块通过export向外输出了一个变量。一个模块也可以同时往外面输出多个变量。
var name = 'Radinbow';
var age = '24';
export{name,age};
导出函数
//myModule.js
export fuction myModule(someArg){
return someArg;
}
导入(import)
定义好模块的输出以后就可以在另外一个模块通过import引用
import {myModule} from 'myModule'; //main.js
import {name,age} from 'test'
//一条import语句可以同时导入默认函数和其它变量
import defaultMethod,{otherMethod} from 'xxx.js';
箭头(Arrow)函数
这是ES6最令人激动的特性之一。=>不只是关键字function的简写,还带来了其它好处。箭头函数与包围它的代码共享一个this,能帮你很好的解决this的指向问题。有经验的javaScript开发者都熟悉如 var self = this;或var that = this这种引用外围this的模式。但借助=>,就不需要这种模式了。
箭头函数的结构
//箭头前空括号
()=> 1
//箭头前单个函数体
v=>v+1
//箭头前括号里面多个参数名,箭头后一个表达式作为函数返回值
(a,b)=>a+b
//花括号括起来的函数体,返回undefined
()=>{
alert("foo");
}
//花括号括起来的函数体,自行return
e=>{
if(e == 0){
return 0;
}
return 1;
}
卸载监听器的陷阱
不论是函数还是bind,每次执行返回的都是一个新的函数引用,因为如果你需要用这个函数去做一些别的事情,比如卸载监听器,那么你需要保存这个引用。
错误做法
由于this.onAppPaused.bind(this)每次执行都会返回一个新的引用,导致无法移除监听器
class PauseMenu extends React.Component{
componentWillMount() {
AppStateIOS.addEventListener('change',this.onAppPaused.bind(this));
}
componentWillUnmount() {
AppStateIOS.removeEventListener('change',this.onAppPaused.bind(this));
}
onAppPaused(event){
}
}
正确的做法
class PauseMenu extends React.Component{
constructor(props){
super(props);
this._onAppPaused = this.onAppPaused.bind(this);
}
componentWillMount() {
AppStateIOS.addEventListener('change',this._onAppPaused);
}
componentWillUnmount() {
AppStateIOS.removeEventListener('change',this._onAppPaused);
}
onAppPaused(event){
}
}
除了以上做法,还可以
class PauseMenu extends React.Component{
componentWillMount() {
AppStateIOS.addEventListener('change',this.onAppPaused);
}
componentWillUnmount() {
AppStateIOS.removeEventListener('change',this.onAppPaused);
}
//把函数直接作为一个arrow function的属性来定义,初始化的时候就绑定好了this指针。
onAppPaused = (event) =>{
}
}
函数参数的默认值
function foo(height = 50,color = 'red'){
}
//不使用默认值
function foo(height,color){
var height = height || 50;
var color = color || 'red';
}
这样写一般没有问题,但是当我们的参数为false的时候,就会出现一些问题。比如 foo(0,""),这样会导致height取值50,color取值red。
模板字符串
https://www.jianshu.com/p/287231fbbc71
解构赋值
解构赋值语法是JavaScript中的一种表达式,可以方便的从数组或者对象中快速提取赋值给定义的变量。
获取数组中的值
从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。
var foo = ["one","two","three","four"];
var [one,two,three] = foo;
console.log(one); //"one"
console.log(two); //"two"
console.log(three); //"three"
//如果你要忽略某些值
var [first,,last] = foo;
console.log(first); // "one"
console.log(last); // "four"
//也可以这么写
var a,b; //先申明变量
[a,b] = [1,2];
console.log(a); // 1
console.log(b); // 2
如果你没有从数组中的获取到值,你可以为变量设置一个默认值
var a,b;
[a=5,b=7] = [1];
console.log(a); // 1
console.log(b); // 7
通过结构赋值可以方便的交换两个变量的值
var a = 1;
var b = 3;
[a,b] = [b,a];
console.log(a); // 3
console.log(b); // 1
获取对象中的值
const student = {
name:'Ming',
age:'18',
city:'Shanghai'
};
const {name,age,city} = student;
console.log(name); //"Ming"
console.log(age); // "18"
console.log(city); // "Shanghai"
延展操作符(Spread operator)
延展操作符 ... 可以在函数调用/数组构造时,将数组表达式或者string在语法层次展开;还可以在构造对象时,将对象表达式按key-value的方式展开
语法
函数调用
myFuction(...iterableObj)
数组构造或字符串
[...iterableObj,'4',...'hello',6];
构造对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性)
let objClone = {...obj};
应用场景
在函数调用时使用延展操作符
function sum(x,y,z) {
return x + y + z;
}
const numbers = [1,2,3];
//不使用延展操作符
console.log(sum.apply(null,numbers));
//使用延展操作符
console.log(sum(...numbers)); // 6
构造数组
没有展开语法的时候,只能组合使用push,splice,concat等方法,将已有数组元素变成新数组的一部分,有了展开语法,构造新数组会变得更简单、更优雅。
const students = ['Jine','Tom'];
const persons = ['Tony',...students,'Aaron','Anna'];
console.log(persons);// ['Tony','Jine','Tom','Aaron','Anna'];
和参数列表的展开类似,...在构造字数组时,可以在任意位置多次使用
数组拷贝
var arr = [1,2,3];
var arr2 = [...arr]; //等同于 arr.slice()
arr2.push(4);
console.log(arr2); //[1,2,3,4]
展开语法和Object.assign()行为一致,执行的都是浅拷贝(只遍历一层)
连接多个数组
var arr1 = [0,1,2];
var arr2 = [3,4,5];
var arr3 = [...arr1,...arr2];//将arr2中所有元素附加到arr1后面并返回
//等同于
var arr4 = arr1.concat(arr2);
在ECMA Script2018中延展操作符添加了对对象的支持
var obj1 = {foo:'bar',x:42};
var obj2 = {foo:'baz',y:13};
var clonedObj = {...obj1};
//克隆后的对象:{foo:'bar',x:42}
var mergeObj = {...obj1,...obj2};
//合并后的对象 {foo:'baz',y:13}
React中的应用
通常我们封装一个组件时,会对外公开一些props用于实现功能。大部分情况下在外部使用都应显示的传递props。但是当传递大量的props时,会非常繁琐,我们这时候可以使用 ...(延展操作符,用于取出参数对象的所有可遍历属性)来进行传递。
一般情况下我们应该这样写
<CustomComponent name='Jine' age={21}/>
//使用...,等同于上面的写法
const params = {
name : 'Jine',
age : 21
}
<CustomComponent {...params}/>
//配合结构赋值避免传入一些不需要的参数
var params = {
name : '123',
title : '456',
type : 'aaa'
}
var {type,...other} = params;
<CustomComponent type='normal' number={2} {...other}/>
//等同于
<CustomComponent type='normal' number={2} name='123' title='456'/>
对象属性简写
在ES6中允许我们在设置一个对象的属性的时候不指定属性名。
//不使用ES6
const name='Ming',age='18',city='Shanghai';
const student = {
name:name,
age:age,
city:city
};
console.log(student) // {name:'Ming',age='18',city='Shanghai'}
//对象中必须包含属性和值,显得非常冗余,使用ES6
const name='Ming',age='18',city='Shanghai';
const student = {
name,
age,
city
};
console.log(student) // {name:'Ming',age='18',city='Shanghai'}
Promise
Promise是异步编程的一种解决方法,比传统的解决方案callback更加的优雅。它最早由社区提出和实现的,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
//不使用ES6
//嵌套两个setTimeout回调函数
setTimeout(function(){
console.log('Hello'); //1秒后输出"Hello"
setTimeout(function(){
console.log('Hi'); //2秒后输出"Hi"
},2000)
},1000);
//使用ES6
var waitSecond = new Promise(function (resolve,reject) {
setTimeout(resolve,1000);
})
waitSecond
.then(function () {
console.log("Hello"); // 1s后输出"Hello"
return waitSecond;
})
.then(function () {
console.log("Hi"); // 2s后输出"Hi"
});
上面的代码使用两个then来进行异步编程串行化,避免了回调地狱。
ES7特性
Array.prototype.includes()
includes() 函数用来判断一个数组是否包含指定的值,包含返回true,反之false。
includes 函数与 indexOf 函数很相似,下面表达式等价
arr.includes(x)
arr.indexOf(x) >= 0
指数操作符
ES7中引入指数操作符 ** 等价于 Math.pow(..)