1. 介绍
    ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会)在标准ECMA-262中定义的脚本语言规范。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMA-262标准的实现和扩展。

    历史版本
    至发稿日为止有九个ECMA-262版本发表。其历史版本如下:

    1997年6月:第一版
    1998年6月:修改格式,使其与ISO/IEC16262国际标准一样
    1999年12月:强大的正则表达式,更好的词法作用域链处理,新的控制指令,异常处理,错误定义更加明确,数据输出的格式化及其它改变
    2009年12月:添加严格模式("use strict")。修改了前面版本模糊不清的概念。增加了getters,setters,JSON以及在对象属性上更完整的反射。
    2011年6月:ECMAScript标5.1版形式上完全一致于国际标准ISO/IEC 16262:2011。
    2015年6月:ECMAScript 2015(ES2015),第 6 版,最早被称作是 ECMAScript 6(ES6),添加了类和模块的语法,其他特性包括迭代器,Python风格的生成器和生成器表达式,箭头函数,二进制数据,静态类型数组,集合(maps,sets 和 weak maps),promise,reflection 和 proxies。作为最早的 ECMAScript Harmony 版本,也被叫做ES6 Harmony。
    2016年6月:ECMAScript 2016(ES2016),第 7 版,多个新的概念和语言特性。
    2017年6月:ECMAScript 2017(ES2017),第 8 版,多个新的概念和语言特性。
    2018年6月:ECMAScript 2018 (ES2018),第 9 版,包含了异步循环,生成器,新的正则表达式特性和 rest/spread 语法。
    2019年6月:ECMAScript 2019 (ES2019),第 10 版。
    发展标准
    TC39(Technical Committee 39)是一个推动JavaScript发展的委员会,它的成语来自各个主流浏览器的代表成语。会议实行多数决,每一项决策只有大部分人同意且没有强烈反对才能去实现。

    TC39成员制定着ECMAScript的未来。

    每一项新特性最终要进入到ECMAScript规范里,需要经历5个阶段,这5个阶段如下:

    Stage 0: Strawperson

    只要是TC39成员或者贡献者,都可以提交想法

    Stage 1: Proposal

    这个阶段确定一个正式的提案

    Stage 2: draft

    规范的第一个版本,进入此阶段的提案大概率会成为标准

    Stage 3: Candidate

    进一步完善提案细则

    Stage 4: Finished

    表示已准备好将其添加到正式的ECMAScript标准中

    由于ES6以前的属性诞生年底久远,我们使用也比较普遍,遂不进行说明,ES6之后的语言风格跟ES5以前的差异比较大,所以单独拎出来做个记录。

    ES6(ES2015)
    ES6是一次重大的革新,比起过去的版本,改动比较大,本文仅对常用的API以及语法糖进行讲解。

    Let 和 Const
    在ES6以前,JS只有var一种声明方式,但是在ES6之后,就多了let跟const这两种方式。用var定义的变量没有块级作用域的概念,而let跟const则会有,因为这三个关键字创建是不一样的。

    区别如下:

    {
    var a = 10
    let b = 20
    const c = 30
    }
    a // 10
    b // Uncaught ReferenceError: b is not defined
    c // c is not defined
    let d = 40
    const e = 50
    d = 60
    d // 60
    e = 70 // VM231:1 Uncaught TypeError: Assignment to constant variable.

    var let const

      var let const
    变量提升 × ×
    全局变量 × ×
    重复声明 × ×
    重新赋值 ×
    暂时死区 ×
    块作用域 ×
    只声明不初始化 ×

    类(Class)
    在ES6之前,如果我们要生成一个实例对象,传统的方法就是写一个构造函数,例子如下:

    1 function Person(name, age) {
    2 this.name = name
    3 this.age = age
    4 }
    5 Person.prototype.information = function () {
    6 return 'My name is ' + this.name + ', I am ' + this.age
    7 }

    但是在ES6之后,我们只需要写成以下形式:

    class Person {
    constructor(name, age) {
    this.name = name
    this.age = age
    }
    information() {
    return 'My name is ' + this.name + ', I am ' + this.age
    }
    }

    箭头函数(Arrow function)
    箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。

    在ES6以前,我们写函数一般是:

    var list = [1, 2, 3, 4, 5, 6, 7]
    var newList = list.map(function (item) {
    return item * item
    })

    但是在ES6里,我们可以:

    const list = [1, 2, 3, 4, 5, 6, 7]
    const newList = list.map(item => item * item)

    看,是不是简洁了不少

    函数参数默认值(Function parameter defaults)
    在ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:

    function config (data) {
    var data = data || 'data is empty'
    }

    这样看起来也没有问题,但是如果参数的布尔值为falsy时就会出问题,例如我们这样调用config:

    config(0)
    config('')

    那么结果就永远是后面的值

    如果我们用函数参数默认值就没有这个问题,写法如下:

    const config = (data = 'data is empty') => {}

    模板字符串(Template string)
    在ES6之前,如果我们要拼接字符串,则需要像这样:

    var name = 'kris'
    var age = 24
    var info = 'My name is ' + this.name + ', I am ' + this.age

    但是在ES6之后,我们只需要写成以下形式:

    const name = 'kris'
    const age = 24
    const info = `My name is ${name}, I am ${age}`

    解构赋值(Destructuring assignment)
    我们通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

    比如我们需要交换两个变量的值,在ES6之前我们可能需要:

    var a = 10
    var b = 20
    var temp = a
    a = b
    b = temp

    但是在ES6里,我们有:

    let a = 10
    let b = 20
    [a, b] = [b, a]

    是不是方便很多

    模块化(Module)
    在ES6之前,JS并没有模块化的概念,有的也只是社区定制的类似CommonJS和AMD之类的规则。例如基于CommonJS的NodeJS:

    // circle.js
    // 输出
    const { PI } = Math
    exports.area = (r) => PI * r ** 2
    exports.circumference = (r) => 2 * PI * r

    // index.js
    // 输入
    const circle = require('./circle.js')
    console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`)

    在ES6之后我们则可以写成以下形式:

    // circle.js
    // 输出
    const { PI } = Math
    export const area = (r) => PI * r ** 2
    export const circumference = (r) => 2 * PI * r

    // index.js
    // 输入
    import {
    area
    } = './circle.js'
    console.log(`半径为 4 的圆的面积是: ${area(4)}`)

    扩展操作符(Spread operator)
    扩展操作符可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。

    比如在ES5的时候,我们要对一个数组的元素进行相加,在不使用reduce或者reduceRight的场合,我们需要:

    function sum(x, y, z) {
    return x + y + z;
    }
    var list = [5, 6, 7]
    var total = sum.apply(null, list)

    但是如果我们使用扩展操作符,只需要如下:

    const sum = (x, y, z) => x + y + z
    const list = [5, 6, 7]
    const total = sum(...list)

    非常的简单,但是要注意的是扩展操作符只能用于可迭代对象

    如果是下面的情况,是会报错的:

    var obj = {'key1': 'value1'}
    var array = [...obj] // TypeError: obj is not iterable

    对象属性简写(Object attribute shorthand)
    在ES6之前,如果我们要将某个变量赋值为同样名称的对象元素,则需要:

    var cat = 'Miaow'
    var dog = 'Woof'
    var bird = 'Peet peet'

    var someObject = {
    cat: cat,
    dog: dog,
    bird: bird
    }

    但是在ES6里我们就方便很多:

    let cat = 'Miaow'
    let dog = 'Woof'
    let bird = 'Peet peet'

    let someObject = {
    cat,
    dog,
    bird
    }

    console.log(someObject)

    //{
    // cat: "Miaow",
    // dog: "Woof",
    // bird: "Peet peet"
    //}

    非常方便

    Promise
    Promise 是ES6提供的一种异步解决方案,比回调函数更加清晰明了。

    Promise 翻译过来就是承诺的意思,这个承诺会在未来有一个确切的答复,并且该承诺有三种状态,分别是:

    等待中(pending)
    完成了 (resolved)
    拒绝了(rejected)
    这个承诺一旦从等待状态变成为其他状态就永远不能更改状态了,也就是说一旦状态变为 resolved 后,就不能再次改变

    new Promise((resolve, reject) => {
    resolve('success')
    // 无效
    reject('reject')
    })

    当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的

    new Promise((resolve, reject) => {
    console.log('new Promise')
    resolve('success')
    })
    console.log('finifsh')
    // new Promise -> finifsh

    Promise 实现了链式调用,也就是说每次调用 then 之后返回的都是一个 Promise,并且是一个全新的 Promise,原因也是因为状态不可变。如果你在 then 中 使用了 return,那么 return 的值会被 Promise.resolve() 包装

    Promise.resolve(1)
    .then(res => {
    console.log(res) // => 1
    return 2 // 包装成 Promise.resolve(2)
    })
    .then(res => {
    console.log(res) // => 2
    })

    当然了,Promise 也很好地解决了回调地狱的问题,例如:

    ajax(url, () => {
    // 处理逻辑
    ajax(url1, () => {
    // 处理逻辑
    ajax(url2, () => {
    // 处理逻辑
    })
    })
    })
    可以改写成:

    ajax(url)
    .then(res => {
    console.log(res)
    return ajax(url1)
    }).then(res => {
    console.log(res)
    return ajax(url2)
    }).then(res => console.log(res))
    for...of
    for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

    例子如下:

    const array1 = ['a', 'b', 'c'];

    for (const element of array1) {
    console.log(element)
    }

    // "a"
    // "b"
    // "c"
    Symbol
    symbol 是一种基本数据类型,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。

    每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。

    例子如下:

    const symbol1 = Symbol();
    const symbol2 = Symbol(42);
    const symbol3 = Symbol('foo');

    console.log(typeof symbol1); // "symbol"
    console.log(symbol3.toString()); // "Symbol(foo)"
    console.log(Symbol('foo') === Symbol('foo')); // false
    迭代器(Iterator)/ 生成器(Generator)
    迭代器(Iterator)是一种迭代的机制,为各种不同的数据结构提供统一的访问机制。任何数据结构只要内部有 Iterator 接口,就可以完成依次迭代操作。

    一旦创建,迭代器对象可以通过重复调用next()显式地迭代,从而获取该对象每一级的值,直到迭代完,返回{ value: undefined, done: true }

    虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 function*语法编写。 最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。

    可以根据需要多次调用该函数,并且每次都返回一个新的Generator,但每个Generator只能迭代一次。

    所以我们可以有以下例子:

    function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
    for (let i = start; i < end; i += step) {
    yield i;
    }
    }
    var a = makeRangeIterator(1,10,2)
    a.next() // {value: 1, done: false}
    a.next() // {value: 3, done: false}
    a.next() // {value: 5, done: false}
    a.next() // {value: 7, done: false}
    a.next() // {value: 9, done: false}
    a.next() // {value: undefined, done: true}
    Set/WeakSet
    Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

    所以我们可以通过Set实现数组去重

    const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
    console.log([...new Set(numbers)])
    // [2, 3, 4, 5, 6, 7, 32]
    WeakSet 结构与 Set 类似,但区别有以下两点:

    WeakSet 对象中只能存放对象引用, 不能存放值, 而 Set 对象都可以。
    WeakSet 对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样, WeakSet 对象是无法被枚举的, 没有办法拿到它包含的所有元素。
    所以代码如下:

    var ws = new WeakSet()
    var obj = {}
    var foo = {}

    ws.add(window)
    ws.add(obj)

    ws.has(window) // true
    ws.has(foo) // false, 对象 foo 并没有被添加进 ws 中

    ws.delete(window) // 从集合中删除 window 对象
    ws.has(window) // false, window 对象已经被删除了

    ws.clear() // 清空整个 WeakSet 对象
    Map/WeakMap
    Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。

    例子如下,我们甚至可以使用NaN来作为键值:

    var myMap = new Map();
    myMap.set(NaN, "not a number");

    myMap.get(NaN); // "not a number"

    var otherNaN = Number("foo");
    myMap.get(otherNaN); // "not a number"
    WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

    跟Map的区别与Set跟WeakSet的区别相似,具体代码如下:

    var wm1 = new WeakMap(),
    wm2 = new WeakMap(),
    wm3 = new WeakMap();
    var o1 = {},
    o2 = function(){},
    o3 = window;

    wm1.set(o1, 37);
    wm1.set(o2, "azerty");
    wm2.set(o1, o2); // value可以是任意值,包括一个对象
    wm2.set(o3, undefined);
    wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个WeakMap对象
    wm1.get(o2); // "azerty"
    wm2.get(o2); // undefined,wm2中没有o2这个键
    wm2.get(o3); // undefined,值就是undefined

    wm1.has(o2); // true
    wm2.has(o2); // false
    wm2.has(o3); // true (即使值是undefined)

    wm3.set(o1, 37);
    wm3.get(o1); // 37
    wm3.clear();
    wm3.get(o1); // undefined,wm3已被清空
    wm1.has(o1); // true
    wm1.delete(o1);
    wm1.has(o1); // false
    Proxy/Reflect
    Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

    Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 Proxy 的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

    Proxy跟Reflect是非常完美的配合,例子如下:

    const observe = (data, callback) => {
    return new Proxy(data, {
    get(target, key) {
    return Reflect.get(target, key)
    },
    set(target, key, value, proxy) {
    callback(key, value);
    target[key] = value;
    return Reflect.set(target, key, value, proxy)
    }
    })
    }

    const FooBar = { open: false };
    const FooBarObserver = observe(FooBar, (property, value) => {
    property === 'open' && value
    ? console.log('FooBar is open!!!')
    : console.log('keep waiting');
    });
    console.log(FooBarObserver.open) // false
    FooBarObserver.open = true // FooBar is open!!!
    当然也不是什么都可以被代理的,如果对象带有configurable: false 跟writable: false 属性,则代理失效。

    Regex对象的扩展
    正则新增符号
    i 修饰符

    // i 修饰符
    /[a-z]/i.test('\u212A') // false
    /[a-z]/iu.test('\u212A') // true
    y修饰符

    // y修饰符
    var s = 'aaa_aa_a';
    var r1 = /a+/g;
    var r2 = /a+/y;

    r1.exec(s) // ["aaa"]
    r2.exec(s) // ["aaa"]

    r1.exec(s) // ["aa"]
    r2.exec(s) // null
    String.prototype.flags

    // 查看RegExp构造函数的修饰符
    var regex = new RegExp('xyz', 'i')
    regex.flags // 'i'
    unicode模式

    var s = '

    从ES6到ES10的新特性万字大总结的更多相关文章

    1. 从 ES6 到 ES10 的新特性万字大总结

      以下文章来源于鱼头的Web海洋 ,作者陈大鱼头   鱼头的Web海洋 一个名为Web的海洋世界 (给前端大全加星标,提升前端技能) 作者:鱼头的Web海洋 公号 / 陈大鱼头 (本文来自作者投稿) 介 ...

    2. Atitit mac os 版本 新特性 attilax大总结

      Atitit mac os 版本 新特性 attilax大总结 1. Macos概述1 2. 早期2 2.1. Macintosh OS (系统 1.0)  1984年2 2.2. Mac OS 7. ...

    3. atitit.atiLinq v2新特性attilax大总结 q326

      atitit.atiLinq v2新特性attilax大总结 q326 1. V3规划 (分开sql2obj sql2sql sql2xml)1 2. V2新特性 Url linq的定义1 3. V1 ...

    4. es6/es7/es8常用新特性总结(超实用)

      本文标题有误导性,因为我其实想写node8的新特性,说实话一下子从node v1.x跳跃到node 8.x+ 真有点受宠若惊的感觉.一直觉得node 数组. 对象.序列等的处理没有python方便,因 ...

    5. Redis4.0新特性之-大KEY删除

      接上一篇,我们得知了redis中存在大KEY,那么这个大KEY如何删除呢?本文将从源码角度分析Redis4.0带来的新特性. 在Redis中,对于大KEY的删除一直是个比较头疼的问题,为了不影响服务, ...

    6. ES6中的一些新特性

      这两个命令是ES6的新语法知识.这两个新的特性解决了ES6中的一些小的"bug"问题.其中包含一些知识:块级作用域.let命令.const命令.全局对象的属性.Google V8引 ...

    7. es6中的部分新特性

      1.es6中变量声明可以使用let声明变量,用const声明常量.例: test:function(){ { var num=10; let num1=11; const num2=12; } con ...

    8. ES6语法:函数新特性(一)

      ES6 函数 引言: 函数在任何语言中偶读很重要,java里面的函数通常叫做方法,其实是一个东西,使用函数可以简化更多的代码,代码结构看着更加清晰.今天我们来学学ES6语法中,函数有什么变化. 虽然现 ...

    9. ES6那些事半功倍的新特性(一)

      数组方面 Array.from(xxx):把json格式字符串转换成数组: Array.of(x,x,x):负责把一堆文本或者变量转换成数组 find( ):该方法为实例方法,就是以Array对象开头 ...

    随机推荐

    1. Git的基本使用 -- 分支管理

      查看分支 git branch 前面带 * 的为当前所在分支 创建分支 git branch 分支名 切换分支 git checkout 分支名 创建并切换到此分支 git checkout -b 分 ...

    2. 配置本地https

      参考 https://juejin.im/post/5a6db896518825732d7fd8e0 https://juejin.im/post/590ec765a22b9d0058fcfaa5 比 ...

    3. HTML的背景

      HTML HTML(超文本标记语言),超文本包括:文字.图片.音频.视频.动画等. W3C(万维网联盟)标准包括: 结构化标准语言(HTML.XML) 1.1. HTML(超文本标记语言):用来显示数 ...

    4. 路飞-Redis的使用,登录注册接口

      复习 """ 1.git项目开发 提供公钥成为开发者.copy项目.开发项目 先commit.再pull(可能出现冲突).最后push 特殊功能可以新建dev的子分支进行 ...

    5. 2.springboot------微服务

      什么是微服务? 微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合:可以通过http的方式进行互通.要说微服务架构,先得说说过去我们的单体应用架构. 单体应用架 ...

    6. Poj1328Radar Installation雷达安装

      原题链接 经典贪心,转化为问题为,对于所有的区间,求最小的点数能使每个区间都至少有一个点. #include<iostream> #include<cstdio> #inclu ...

    7. 【Markdown】新手快速入门基础教程

      Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档.当前许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息.例如:GitHub.简书.reddi ...

    8. AJAX-状态属性

      XMLHttpRequest对象的readyState属性 作用:表示xhr对象的请求状态 值:由0到4表示5个状态 0:请求尚未初始化 1:已经打开到WEB服务器的连接,正在向服务器发送请求 2:请 ...

    9. 浅谈ABB机器人(工具坐标,工件坐标,有效载荷)

      工具坐标(tool): 使tcl坐标偏移到工具上,例如焊接工作,使机器人工作点切入焊枪点上 mass:工具的重量 xyz:偏移距离的大小 验证:通过手动模式,切换至自定义工具,重定向 工件坐标(wob ...

    10. C语言程序设计100例之(28):直线蛇形阵

      例28        直线蛇形阵 问题描述 编写程序,将自然数1.2.….N2按蛇形方式逐个顺序存入N阶方阵.例如,当N=3和N=4时的直线蛇形阵如下图1所示. 图1  直线蛇形阵 输入格式 一个正整 ...