以下文章来源于鱼头的Web海洋 ,作者陈大鱼头

 
鱼头的Web海洋

一个名为Web的海洋世界

(给前端大全加星标,提升前端技能)

作者:鱼头的Web海洋 公号 / 陈大鱼头 (本文来自作者投稿)

介绍

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

历史版本

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

1.1997年6月:第一版2.1998年6月:修改格式,使其与ISO/IEC16262国际标准一样3.1999年12月:强大的正则表达式,更好的词法作用域链处理,新的控制指令,异常处理,错误定义更加明确,数据输出的格式化及其它改变4.2009年12月:添加严格模式("use strict")。修改了前面版本模糊不清的概念。增加了getters,setters,JSON以及在对象属性上更完整的反射。5.2011年6月:ECMAScript标5.1版形式上完全一致于国际标准ISO/IEC 16262:2011。6.2015年6月:ECMAScript 2015(ES2015),第 6 版,最早被称作是 ECMAScript 6(ES6),添加了类和模块的语法,其他特性包括迭代器,Python风格的生成器和生成器表达式,箭头函数,二进制数据,静态类型数组,集合(maps,sets 和 weak maps),promise,reflection 和 proxies。作为最早的 ECMAScript Harmony 版本,也被叫做ES6 Harmony。7.2016年6月:ECMAScript 2016(ES2016),第 7 版,多个新的概念和语言特性。8.2017年6月:ECMAScript 2017(ES2017),第 8 版,多个新的概念和语言特性。9.2018年6月:ECMAScript 2018 (ES2018),第 9 版,包含了异步循环,生成器,新的正则表达式特性和 rest/spread 语法。10.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之后,就多了letconst这两种方式。用var定义的变量没有块级作用域的概念,而letconst则会有,因为这三个关键字创建是不一样的。

区别如下:

{        let b =     }a // 10b // Uncaught ReferenceError: b is not definedc // c is not definedlet d = 40const e = 50d = 60d // 60e = 70 // VM231:1 Uncaught TypeError: Assignment to constant variable.
  var let const
变量提升 × ×
全局变量 × ×
重复声明 × ×
重新赋值 ×
暂时死区 ×
块作用域 ×
只声明不初始化 ×

类(Class)

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

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

但是在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)

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

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

, , , , , , ]var newList = list.map(function (item) {    return item * item})

但是在ES6里,我们可以:

, , , , , , ]const newList = list.map(item => item * item)

看,是不是简洁了不少

函数参数默认值(Function parameter defaults)

在ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:

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

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

config()config('')

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

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

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

模板字符串(Template string)

在ES6之前,如果我们要拼接字符串,则需要像这样:

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

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

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

解构赋值(Destructuring assignment)

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

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

var a = 10var b = 20var temp = aa = bb = temp

但是在ES6里,我们有:

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

是不是方便很多

模块化(Module)

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

// circle.js// 输出const { PI } = Mathexports.area = (r) => PI * r ** 2exports.circumference = (r) => 2 * PI * r
// index.js// 输入const circle = require('./circle.js')console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`)

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

// circle.js// 输出const { PI } = Mathexport const area = (r) => PI * r ** 2export 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) {    , , ]var total = sum.apply(null, list)

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

, , ]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 翻译过来就是承诺的意思,这个承诺会在未来有一个确切的答复,并且该承诺有三种状态,分别是:

1.等待中(pending)2.完成了 (resolved)3.拒绝了(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()  .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 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*[2]语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。

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

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

function* makeRangeIterator(start = , end = Infinity, step = ) {    ,,)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实现数组去重

,,,,,,,,,,,,,,,,,,]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) // truews.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的区别与SetWeakSet的区别相似,具体代码如下:

var wm1 = new WeakMap(),    wm2 = new WeakMap(),    wm3 = new WeakMap();var o1 = {},    o2 = function(){},    o3 = window;
wm1.);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); // truewm2.has(o2); // falsewm2.has(o3); // true (即使值是undefined)
wm3.);wm3.get(o1); // 37wm3.clear();wm3.get(o1); // undefined,wm3已被清空wm1.has(o1);   // truewm1.delete(o1);wm1.has(o1);   // false

Proxy/Reflect

Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

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

ProxyReflect是非常完美的配合,例子如下:

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) // falseFooBarObserver.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的新特性万字大总结

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

  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. FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated;

    /Users/jerryqi/PycharmProjects/DeepLearning/venv/lib/python3.7/site-packages/tensorflow/python/frame ...

  2. java输入输出 -- java NIO之缓存区Buffer

    一.简介 java NIO相关类在jdk1.4被引入,用于提高I/O的效率.java NIO包含很多东西,但核心的东西不外乎Buffer.channel和selector.本文先来看Buffer的实现 ...

  3. ElasticSearch入门-基本概念介绍以及安装

    Elasticsearch基本概念 Elasticsearch是基于Lucene的全文检索库,本质也是存储数据,很多概念与传统关系型数据库类似. 传统关系型数据库与Elasticsearch进行概念对 ...

  4. 下载GDB调试工具peda

    命令: 1.git clone https://github.com/longld/peda.git ~/peda 2.echo "source ~/peda/peda.py" & ...

  5. ActiveMQ 消息确认

    一.事务性会话:当一个事务被提交的时候,确认自动发生 ConnectionFactory connectionFactory=new ActiveMQConnectionFactory("t ...

  6. Windows 32位-调试与反调试

    1.加载调试符号链接文件并放入d:/symbols目录下. 0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/s ...

  7. PHP迭代生成器---yield

    1.迭代生成器 生成器的核心是一个yield关键字,一个生成器函数看起来像一个普通的函数,不同的是:普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值.生成器函数被调用时,返回的是一个 ...

  8. pycharm使用pylint

    # 与能查到的多数博文做法不太一样,自认为这样更简单有效 1. 下载插件 https://plugins.jetbrains.com/plugin/11084-pylint 2. 从磁盘安装插件 注意 ...

  9. Neo4j基本使用及导入三元组

    下载和安装Neo4j 安装Java JDK 下载Neo4j安装文件 创建系统环境变量 Neo4j配置 配置文档存储在conf目录下,Neo4j通过配置文件neo4j.conf控制服务器的工作.默认情况 ...

  10. (一)SpringMvc简介以及第一个springmvc工程

    一.SpringMVC是什么? springmvc是Spring的一个模块,提供web层解决方案(就与MVC设计架构) 如上图, DispatcherServlet:前端控制器,由SpringMVC提 ...