美文网首页js语法
横向对比ES5、ES6、ES7、ES8

横向对比ES5、ES6、ES7、ES8

作者: 白昔月 | 来源:发表于2019-01-12 17:03 被阅读8次

前言

ECMAScript是由ECMA组织定制的脚本语言规范,大家简称为ES,目前Javascript使用的版本是ECMAScript-262。

ECMAScript其实是建立在网景的Javascript和微软的Jscript之上的,都是由Brendan Eich发明的。因此,ES标准是一种反向制定的标准,程序员们在各个浏览器上用不同的JS语言和不同额JS功能,然后觉得某个浏览器上的功能好,那么就将其写入到ES规范中,并由ES大会定期整理并发布。

es版本 发布时间 新增特性
es 5 200911 扩展了Object、Array、Function等的功能
es5(2015) 201506 类、模块化、剪头函数、函数参数默认值、模版字符串、解构赋值、延展操作符、对象属性简写、Promise、let、const
es7(2016) 201603 Array.prototype.includes()、指数操作符
es8(2017) 201706 async/await、Object.values()、Object.entries()、String padding、函数参数列表结尾允许逗号、Object.getOwnPropertyDescriptors()等

ES5我就不说了,主要说说其他几个都更新了什么

部分ES6 新增特性说明

JS语言原来实现面向对象是直接通过原型的方式进行,这就让Java、Object-c、C#等面向对象语言的程序员比较难以理解了。随着JS能做的事情增多,因此,才会原生的引入class这个概念。我们来看看下边这段代码,来看看类与继承的代码如何写,此次需要注意的是,继承的时候,super要写在子类构造函数的最顶部。

class Animal {
    constructor(name, feature) {
        this.name = name
        this.feature = feature
    }

    toString() {
        console.log('name:' + this.name + ',feature:' + this.feature)
        // return 'Animal done'
    }
}

var animal = new Animal('monky', 'beauty')//实例化
animal.toString()

console.log(animal.hasOwnProperty('name'))//true
console.log(animal.hasOwnProperty('toString'))//false
console.log(animal.__proto__.hasOwnProperty('toString'))//true

//继承

class Cat extends Animal {
    constructor(action) {
        super('cat', 'sex')
        this.action = action
    }

    toString(){
        // console.log(super.toString())
        super.toString()
    }
}

var cat = new Cat('catch')
cat.toString()

console.log(cat instanceof Cat)//true
console.log(cat instanceof Animal)//true

模块化(Module)

模块化主要基于export(导出)和import(引用)两个关键字来实现,这就为JS引入了一个相对容易理解的封装的概念(以前是基于函数作用域和闭包,通过底层直接实现,现在可以优雅的通过关键字原生实现)

export定义了对外开放的接口,import定义了引用哪些接口。模块化为js创建了比较容易理解的命名空间,防止函数的命名冲突。

export

export var name = 'Ryan'//导出变量
export const sort = Math.sqrt//导出常量
export {name, sort}//导出对象(模块)
export function aModule(){return 1000}//导出函数

import

import defaultMethod,{otherMethod} from 'aModule'//xxx.js

箭头(Arrow)函数

1.=>是function的缩写
2.箭头函数与包围它的代码共享同一个this。这种情况下,就很好的解决了this的指向问题。我在写一个钱包服务器的时候,做过这样一个事情,通过定义var self = this,或者var that = this来引用外围的this,也就是我想用其他function中的this,我就需要想将其复制到一个全局的或者是类的属性上。借助=>,就不需要这种模式了。箭头函数的书写形式如下

()=>100
v=>x+1
(a,b)=>a-b
()=>{var=u}//return undefined
p=>{return 100}

箭头函数与bind的注意事项

箭头函数和bind方法,每次被执行后都会返回一个新的函数引用,因此,如果还需要对函数的引用做些事情的话(例如卸载监听器),那么你还需要保存之前的引用。以bind为例,我们说明一下:

class PauseMenu extends React.Component {
    componentWillMount() {
        AppStateIOS.addEventListener('change', this.onAppPaused.bind(this))
    }
    componentWillUnmount() {
        AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this))
    }
    onAppPaused(event) { }
}

此处,因为bind每次都会调用一个新的函数引用,因此,造成卸载的不是原来的监听,造成卸载失败。此处应该修改为

class PauseMenu extends React.Component {
    constructor(props) {
        super(porps)
        this._onAppPaused = this.onAppPaused.bind(this)
    }
    componentWillMount() {
        AppStateIOS.addEventListener('change', this._onAppPaused)
    }
    componentWillUnmount() {
        AppStateIOS.removeEventListener('change', this._onAppPaused)
    }
    onAppPaused(event) { }
}

那么基于剪头函数,我们还可以使用箭头函数来做,因为箭头函数会共享包围它的this,因此,这样就可以简单明了的处理返回新的函数引用的问题了。

class PauseMenu extends React.Component {
    componentWillMount() {
        AppStateIOS.addEventListener('change', this.onAppPaused)
    }
    componentWillUnmount() {
        AppStateIOS.removeEventListener('change', this.onAppPaused)
    }
    onAppPaused = event => { }
}

函数参数默认值

function foo(height = 50,color = '#fff")

如果不使用函数默认值,就会有个小问题。

function foo (height,color)
{
var height = height||50
var color = color||'red'
}

如果参数的布尔值是false,例如,foo(0,''),因为0的布尔值是false,这样height的取值将会是50,color也会取red,因此,函数的默认值不仅能使代码简洁,也帮助规避一些风险

模版字符串

var name = 'name'+first+''+last+''

使用模版字符串,就简洁了很多

var name = 'name is ${first} ${last}'

解构赋值

解构赋值可以方便快速的从数组或者对象中提取赋值给定义的变量。

获取数组中的值

从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。

var foo = [1,2,3,4,5]

var [one,twe,three] = foo
console.log(one)//1
console.log(twe)//2
console.log(three)//3

如果想要会略某些值,则可以

var [first,,last] = foo
console.log(first)//1
console.log(last)//5

也可以先声明变量

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:'xxx',
age:'19',
city:'bj'
}

const {name, age,city}=student

console.log(name)//xxx
console.log(age)//19
console.log(city)//bj

延展操作符(Spread operator)

延展操作符 = ...可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开,还可以在构造对象时,将对象表达式按key-value的方式展开。

函数调用

function(...iterableObj)

数组构造或者字符串

[...iterableObj,'4',...'hello',6]

es2018下构造对象时,进行克隆或者属性拷贝

let objClone={...obj}

应用场景

function sum(x,y,x){

return x+y+z

}

const numbers = [1,2,3]

不使用延展操作符

sum.apply(null, numbers)

使用延展操作符

sum(...numbers)

或者在构造数组时

如果没有展开语法,只能组合使用push,splice,concat,slice
将已有数组元素变为新数组的一部分

const people=['jan','tom']
const person = ['ali',...people,'alliance','ketty']
console.log(person)//Ali,jan,tom,alliance,ketty

另外,还有一个例子

var arr =[1,2,3]
var arr2=[...arr]
arr2.push(4)
console.log(arr2)//1,2,3,4

展开语法与Obj.assign()行为一致,都是执行浅拷贝,也就是只遍历一层,不会遍历父对象相关的数据

var arr1=[0,1,2]
var arr2=[3,4,5]
var arr3=[...arr1,...arr2] 等同于var arr4 = arr1.concat(arr2)

es2018中增加了对对象的支持

var obj1 = {foo:1,foo2:2}
var obj2={foo3:12,foo4:30}

var clonedObj={...obj1}
var mergedObj={...obj1,...obj2}

...在react中的应用

我们封装组件的时候,会对外公开props用于参数传递。我们一般都会使用...props进行参数的传递与遍历数据

<CustomComponent name='Jine' age={21} />
等价于
const params = {
name:'jine',
age:21
}

<CustomComponent {...params} />

我们还可以配合结构赋值,避免传入一些不必要的参数

var param = {
name:123,
title:456,
type:789
}

var {type,...other} = param

<CustomComponent type='normal' number={2} {...other} />
等价于

<CustomComponent type='normal' number={2} name=123,title=456/>

对象属性简写

设置一个对象时,不指定属性名

es5
const name=ming,age=18,city=Shanghai
const student={
name:name,
age:age,
city:city
}
es6
const name=ming,age=18,city=Shanghai
const student={
name,
age,
city
}


Promise

Promise是异步编程的一种解决方案,对callback做进一步的封装和优化。Promise由社区提出和实现,es6将其写进了语言标准,并统一了用法,提供了原生的promise支持。此处详细解答,请看我的另外一篇blog

let、const

let、const提供块级作用域,之前只能通过函数+闭包的方式来模拟块级作用域

es5
{var a=19}

console.log(a)//19
es6

{
let a=20
}
console.log(a)//a is not defined


部分ES7新增特性说明

Array.prototype.includes()

用来判断一个数组是否包含指定的值,包含返回true,不包含返回false

arr.includes(x)等价于arr.indexOf(x)>0

指数操作符(**)

** 与Math.pow(..)等效的计算结果

Math.pow(2,10)等价于2**10

部分ES8新增特性说明

async/await

异步转同步,可以看我的另外一片blog。我们主要是用async/await来顺序获取异步函数返回值。
另外,依托于Promise.all还可以实现await的并发调用,这样就避免了同步调用的时间等待,提高了程序的整体效率。

async function charCountAdd(data1, data2) {

    const [d1, d2] = await Promise.all([charCount(data1), charCount(data2)])
    // const d1 = await charCount(data1)
    // const d2 = await charCount(data2)
    return d1 + d2

}

charCountAdd('Hello','Hi').then(console.log)
function charCount(data){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(data.length)
        },5000)
    })
}
//捕捉错误,可以使用try catch,也可以在then后追加catch

Object.values()

Object.values()类似于Object.keys(),返回Object自身的所有属性值,不包括继承的值。

const obj={a:12,b:13,c:14}
es7
const vals=Object.keys(obj).map(key=>obj[key])
console.log(vals)//12,13,14
es8
const vals =Object.values(obj)
console.log(vals)//12,13,14

Object.entries

Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组

const obj={a:12,b:13,c:14}
es7
Object.keys(obj).forEach(key=>{
console.log('key:'+key+'values:'+obj[key])//12,13,14
})
es8
for (let [key,value] of Object.entries(obj)){
console.log('key: ${key} values: ${value}')//12,13,14
}

String padding

es8中,新增String.prototype.padStart(targetLength,[padString])和String.prototype.padEnd允许将空字符串或者其他字符串添加到原始字符串的开头或者结尾

console.log('0.0'.padStart(4,'10'))//10.0
console.log('0.0'.padStart(20))//                    0.0
console.log('0.0'.padEnd(4,'0'))//0.00
console.log('0.0'.padEnd(10,'0'))//0.000000000

编码规范

单引号、双引号

node中,单引号双引号有很多的时候是可以混用的,因此,此处也是一个重点,如果不注意,很容易出现奇怪的错误。在JSON中,全部请使用双引号,在其他地方也请使用双引号,如果在双引号中又存在引号,请使用单引号做区分。

分号

必须记得加分号,不加分号就跟耍流氓一样。

缩进、空格、大括号、小括号、逗号、数组、对象等的基本格式

通过IDE协助缩进,具体方式请根据不同的IDE进行总结,本处简单介绍webstrom的使用方式----全选之后,剪切代码,然后重新粘贴到代码编辑文本输入框中。

变量声明

如果是ES5的话永远都要加var,如果是ES6.....如果是ES7....

命名

变量命名:名词+小驼峰
方法命名:动词开头+名词+小驼峰
类命名(ES6开始有类喽,MD以前都是原型....艹):大驼峰
常量命名:大写字母 + 下划线
文件命名:小写字母 + 下划线
中间件(包)命名:小写字母

==和===

==用于直接比较数值的情况
===用于其他情况

字面量

这个字面量的相关说明来源于朴灵的深入浅出,我在这里做一下搬运工。书中说“请尽量使用{}、[]替代new Object()、new Array(),不要使用string(new String)、bool(new Boolean)、number(new Number)对象类型”,当然,此处应该更多的是针对ES5下的相关语法,如果是ES6、ES7应该完全不一样了。(需要补充ES6、ES7的相关语法和规范)

作用域

依然会存在ES5、ES6、ES7不一致的地方。
ES5中没有块级语句,最多是通过with来增加一个临时的块级变量复用区域,但是with又不是特别安全的。
ES6有了块级区域,变量范围跟java差不多了

数组

数组不要用for in进行循环,详见代码:

var foo = [];
foo[100] = 100;
//循环1
for (var i in foo) {
console.log(i);
}
//循环2
for (var i = 0; i < foo.length; i++) {
console.log(i);
}

循环1只会执行一次,循环2则会执行0~100,因此数组就不要for in 了 ,因为,我们可能希望遍历数组中的全部数据,而不是非undefine的数据。

异步

异步回调第一个参数应该是错误指示。

类与模块

依然会存在ES5、ES6、ES7不一致的地方。(之后做整理)
类继承、导出都不一样。

在es5下,类继承推荐的方式是

function Socket(options){
//....
stream.Stream.call(this);
//....
}

util.inherits(Socket,stream.Stream);

最佳实践的理论

1.注释要写成/** */的形式,方面工具导出
2.遵循原来项目的编码规范
3.基于JSLint或者JSHint进行代码质量管理,可以在编辑器中提醒不规范的信息,我们可以增加.jshintrc文件。这个可以去github上去查找并学习。
4.代码提交的hook脚本,例如precommit,这个需要学习整理。
5.持续集成,一方面,持续集成代表着代码质量的扫描,可以定时扫描或者触发式扫描,另一方面,可以通过集中的平台统计代码质量的好坏趋势,根据统计结果可以判定团队中的个人对编码规范的执行情况,决定用宽松的质量管理还是严格的质量管理。
6.可以使用CoffeeScript规范(编译式的js,还有typescript等),来避免一些不必要的编码规范的问题

说明 规则或方法
空格 利用IDE的排版功能自动增加需要的空格。(+、-、*、/、%、(、)等操作符前后都增加空格)
缩进 利用IDE的排版功能自动增加需要的缩进。与Java编码规范相同
变量声明 使用var声明变量
单引号、双引号 json中必须使用双引号,es5 use strict下也必须使用双引号,其他地方单引号双引号可以随便用
分号 必须增加分号在语句的结尾
变量命名 小驼峰
方法命名 小驼峰,动词开头
类命名 大驼峰
常量命名 都是大写字母,使用下划线隔开每个单词
文件命名 都是小写字母,使用下划线隔开每个单词
对外文件命名 都是小写字母,使用下划线开头,并使用下划线隔开每个单词
包名 都是小写字母,仿照npm库进行包的命名
比较操作 尽量使用===,数值比较可以用==

相关文章

  • 横向对比ES5、ES6、ES7、ES8

    前言 ECMAScript是由ECMA组织定制的脚本语言规范,大家简称为ES,目前Javascript使用的版本是...

  • webpack4-babel转换

    目前浏览器可识别的js是es5部分可识别es6所以为了兼容大部分浏览器,需要将es6 es7 es8转换成es5那...

  • ES7特性

    ES7 没有this 箭头函数对比ES6 ES7 Spread & Rest Operator spread .....

  • Math方法和es新特性

    es6常用 es7新特性 es8新特性 es9新特性 es10新特性

  • 基础-1

    Nest是一个渐进式的Node框架,可以在TypeScript和JavaScript(ES6、ES7、ES8)之上...

  • ES6 新特性

    ES6 在2015年6月正式发布, 2015年6月之后发布的ES版本,包括ES7,ES8,ES9统称ES6 ES6...

  • 【转载】JS语法 ES6、ES7、ES8、ES9、ES10、ES

    原文:JS语法 ES6、ES7、ES8、ES9、ES10、ES11、ES12新特性[https://segment...

  • 关于异步函数的前世今生

    1、ES6、ES7、ES8中关于异步函数的处理办法 JS中常用的实现异步的方法 利用setTimout实现异步 动...

  • 【重温基础】17.WebAPI介绍

    本文是 重温基础 系列文章的第十七篇。今日感受:挑战。 系列目录: 【复习资料】ES6/ES7/ES8/ES9资料...

  • 【重温基础】16.JSON对象介绍

    本文是 重温基础 系列文章的第十六篇。今日感受:静。 系列目录: 【复习资料】ES6/ES7/ES8/ES9资料整...

网友评论

    本文标题:横向对比ES5、ES6、ES7、ES8

    本文链接:https://www.haomeiwen.com/subject/vtycdqtx.html