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. IntelliJ IDEA 2017.3尚硅谷-----缓存和索引的清理

    2. [ASP.NET]Web网站与Web应用程序区别

      [ASP.NET]Web网站与Web应用程序区别   本文链接:https://blog.csdn.net/a954553391/article/details/86403521 前言:在项目开发中, ...

    3. 箭头函数 与 forEach

      array.forEach(function(item,index){ }.bind(this)); 同 array.forEach((item,index) =>{ });

    4. 传奇HERO引擎给装备加套装属性技巧

      装备加套装在复古的版本里比较少,但在1.76极品,轻变传奇,微变传奇和迷失版本里面用得比较多,每个引擎的方法相差不多,但也有一些小区别,今天给大家讲解下HERO引擎加套装的技巧. 第一步:我们打开M2 ...

    5. stm32f103中freertos的tasks基本使用案例及备忘

      基本实例   freetos的在stm32中使用踩了一些坑,事情做完了,就 做个备忘,希望能给后面的人一些借鉴. 先给出一个实际的例子吧. 启动代码 void task_create(void) { ...

    6. 【做题笔记】P1969 积木大赛

      非常感谢 rxz 大佬提供的思路. 首先放个图(rxz 画的) 采用贪心的策略:对于一个期望高度 \(h_i\) ,如果大于 \(h_{i-1}\),那么最终答案要加上二者之差:如果小于或等于,那么说 ...

    7. Python(一):一行解法参考

      #一行快速排序quick_sort = lambda array: array if len(array) <= 1 else quick_sort([item for item in arra ...

    8. python eval() 进行条件匹配

      最近开发一个功能,根据条件表达式过滤数据,其中用到了eval(条件字符串,字典) 发现一个现象: >>> print u"campGrade in [ '\u51cf\u8 ...

    9. springboot整合mybatis连接oracle

      pom.xml: <!-- 链接:https://pan.baidu.com/s/1agHs5vWeXf90r3OEeVGniw 提取码:wsgm --> <dependency&g ...

    10. 什么是this指针?this的几种指向

      在JavaScript中,this指针是在创建时,由系统默认生成的两个隐式参数之一(另一个是arguments). this指针指向与该函数调用进行隐式关联的一个对象,该对象被称为“函数上下文”. t ...