版本 | 发布时间 | 新特性 |
---|---|---|
ES5 | 2009年11月 | 扩展了Object、Array、Function的功能等 |
ES6 | 2015年6月 | 类、模块化、箭头函数、函数参数默认值等 |
ES7 | 2016年3月 | includes,指数操作符 |
ES8 | 2017年6月 | async/await,Object.values(),Object.entries(),String padding等 |
class Animal{
//构造函数,实例化时被调用,不指定则有一个不带参数的默认构造函数。
constructor(name,color){
this.name = name;
this.color = color;
}
//toString 是原型对象上的属性
toString(){
console.log('name:' + this.name + ',color:' + this.color);
}
}
var animal = new Animal('dog','white');//实例化Aniaml
animal.toString();
console.log(animal.hasOwnProperty('name'));//true
console.log(animal.hasOwnProperty('toString'));//false
console.log(animal._proto_.hasOwnProperty('toString'));//true
class Cat extends Aniaml{
constructor(action){
//子类必须在constructor中指定super函数,否则在新建实例时会报错。
//如果没有置顶constructor,默认带super函数的constructor将会被添加。
super('cat','white');
this.action = action;
}
toString(){
console.log(super.toString());
}
}
var cat = new Cat('catch');
cat.toString();
//实例cat时Cat和Animal的实例,和ES5完全一致。
console.log(cat instanceof Cat);//true
console.log(cat instanceof Animal);//true
ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。
模块功能主要由 export 和 import 组成。
每个模块有自己单独的作用域,模块之间的相互调用关系是通过export 来规定模块对外暴露的接口,通过import 来引用其它模块提供的接口。
同时还为模块创造了命名空间,防止函数的命名冲突。
ES6允许在一个模块中使用export来导出多个变量或函数
//test.js
export var name = 'Rainbow';
心得:ES6还可以导出常量。export const sqrt = Math.sqrt;//导出常量
ES6将一个文件视为一个模块,上面的模块通过export向外输出了一个变量。一个模块也可以同时向外面输出多个变量。
//test.js
var name = 'Rainbow';
var age = '24';
export{name,age};
//myModule.js
export function myModule(someArg){
return someArg;
}
定义好模块的输出后就可以在另一个模块通过import引用
import {myModule} from 'myModule';//main.js
import {name,age} from 'test';//test.js
心得:一条import语句可以同时导入默认函数和其它变量。import defaultMethod, { otherMethod } from 'xxx.js' ;
箭头函数与包围它的代码共享同一个this,能帮你很好的解决this的指向问题。有经验的Javascript开发者都熟悉诸如var self = this;
或 var that = this
这种引用外围this的模式。但借助=>
,就不需要这种模式了。
箭头函数的箭头=>之前:是一个空括号、单个的参数名、或用括号括起的多个参数名
箭头之后:可以是一个表达式(作为函数的返回值),或者是用花括号括起的函数体(需要自行通过return来返回值,否则返回的是undefined)
//箭头函数的例子
()=>1;
v=>v+1;
(a,b)=>a+b;
()=>{
alert("foo");
}
e=>{
if(e == 0){
return 0;
}
return 1000/e;
}
不论是箭头函数还是bind,每次被执行都返回的是一个新的函数引用,因此如果你还需要函数的引用去做一些别的事情(譬如卸载监听器),那你必须自己保持这个引用。
错误的做法
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);//保存this,保证添加和移除监听器同一个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);
}
onAppPaused = (event) =>{
//把函数直接作为一个arrow function的属性来定义,初始化的时候就绑定好了this指针
}
}
ES6支持在定义函数时为其设置默认值
function foo(height = 50, color = 'red'){
//...
}
不使用默认值时
function foo(height, color){
var height = height || 50;
var color = color || 'red';
}
这样写一般没问题,但当参数的布尔值为false
时,就会有问题了。比如,我们这样调用foo函数
foo(0, "");
因为0的布尔值为false
,这样的height的取值将是50.同理color的取值为‘red’。
所以说,函数参数默认值
不仅能使代码简洁,同时能规避一些问题。