细数各版本JS的新特性

时间:2021-1-8 作者:admin

ES2015(ES6)

2015JS发展的黄金时间,委员会提出的ES6ES5的基础上增加了大量的新特性。
下面是ES6的主要更新

  • let、const关键字
  • 箭头函数
  • class 类
  • 模块(import/export)
  • 模板语法
  • 函数参数默认值
  • rest参数
  • 数组/对象 解构
  • Promise

Let/Const

ES6增加了let/const关键字用于解决原来只有函数作用域的问题,例如以下:

{
  let a = 10;
  const b = 10;
  var c = 20;
  a = 20;
  b = 30; // Assignment to constant variable
}
a // a is not defined
c // 20

箭头函数

ES5中,我们需要以下面方式定义函数

function sum(value1, value2) {
  return value1 + value2
}

但是在箭头函数中可以写更少的代码,如下:

const sum = (value1, value2) => {
  return value1 + value2;
}

class类

ES5中我们是通过原型的方式定义一个类,在ES6中可以通过class的方式来声明一个类。
下面是ES5用于创建构造函数的方式

function Calcutor(moneyBeforeDiscount) {
  this.moneyBeforeDiscount = moneyBeforeDiscount;
}

Calcutor.prototype.moneyAfterDiscount = function (discountRate) {
  return this.moneyBeforeDiscount * (100-discountRate)/100;
}
const demo = new Calcutor(5000)
console.log(demo.moneyAfterDiscount()); // 4000

下面是ES6的方式创建类

class Calculator{
    constructor(moneyBeforeDiscount){
        this.moneyBeforeDiscount = moneyBeforeDiscount;
    }
    moneyAfterDiscount(discountRate){
        return this.moneyBeforeDiscount * (100-discountRate)/100;
    }
}
const demo = new Calculator(5000);
console.log(demo.moneyAfterDiscount()); // 4000

模块(import/export)

ES6之前,js没有原生的模块管理方式。在ES6中,我们在文件中导出函数和和变量,然后在另外一个文件引入他们。
如下:

// calculator.js
const add = (a, b) => a +b
const multiply = (a, b) => a + b

export {add, multiply}

// App.js
import { add } from './calculator'

console.log(add(2, 3))

模板语法

ES6之前,我们如果需要在把字符串和变量进行拼接,需要向以下的方式进行书写

const count = 3;
const str = 'count: ' + count;

这种方式相当繁琐,于是ES6引入了模板字符串解决上面这个问题

const count = 3;
const str = `count: ${count}`

此外也可以在${}写一些简单的逻辑,如下:

const count = 3;
const str = `count: ${count + 2}`

函数参数默认值

ES6之前不能直接指定函数参数的默认值,只能使用变通的方法:

function log(x, y) {
  if (typeof y === 'undefined') {
    y = 'World';
  }
  console.log(x, y)
})

ES6允许为函数的参数设置默认值,即直接写在参数定义的后面

function log(x, y = 'world') {
  console.log(x, y)
}

rest参数

ES6引入了rest参数,用于获取函数的多余参数,这样就不需要使用arguments对象了。
这是ES6之前的获取多余参数的写法

function getParams() {
  return Array.prototype.slice.call(arguments)
}

使用ES6的语法

function getParams(...params) {
  return params;
}

数组和对象解构扩展

对象和数组的解构通常用于需要从数组或者对象中拿到某个属性值。
如下:


数组解构,let/const后面跟上一堆用中括号[]包裹的变量列表,变量的值为对应位置上的数组元素的值,如下:

const [a, b] = [1, 2]
console.log(a, b) // 1, 2

对象解构就是找到对象对应的属性值然后赋值给变量,如下:

const {x, y} = {x: 1, y: 2}
console.log(x, y) // 1, 2

Promise

Promise通常用于处理例如http请求或者消耗大量时间的程序。Promise可以将结果传递给then函数,then函数处理结果会返回一个Promise,继续调用then进行处理结果,如果抛出错误,可以使用catch进行捕获

fetch('/')
  .then(response => response.json())
  .then(result => {
    console.log(result)
  })

ES2016(ES7)

ES7ES6的基础上主要扩展了一些数组的方法例如.includes(),还有指数运算符**

Array.includes()

const number = [1, 2, 3]
console.log(number.includes(1)); // true
console.log(number.includes(7)); //false

指数运算符

console.log(2** 3)

ES2017(ES8)

ES8添加了关键字async/await,让处理异步程序更加方便。我们能够通过使用它避免面条代码,提高异步代码的可读性
下面是ES6的异步方式

fetch('/')
  .then(response => {
    response.json()
  })
  .then(result => {
    console.log(result)
  })

使用ES8,先给函数添加关键字async,然后在异步代码前添加await,异步代码会block整个js线程,只有异步代码返回结果以后,js才会继续执行,上面代码可以改成以下形式

async function fn() {
  const response = await fetch('/');
  const result = await response.json();
  console.log(result);
}

ES2018(ES9)

ES9没有增加新的东西,但是增强了rest和扩展运算符。

rest运算符

我们在对象属性上使用rest。他简化了从对象中抽取某个属性,剩余属性赋值给另外一个对象的过程,如下:

const options = {
  enabled: true,
  text: 'Hello',
  color: 'red'
}
const {enabled, ...others} = options;
console.log(enabled) // true
console.log(others) // {   text: 'Hello', color: 'red' }

对象的扩展符

在对象前面加扩展运算符...,就会浅浅拷贝当前对象的属性值赋值给新对象

const options = {
  text: 'Hello'
}
const param = {enabled: true, ...options}
console.log(param) // {enabled: true, text: 'Hello', }

ES2019(ES10)

ES10让使用try/catch更加简单,不需要声明一个Error然后去捕获他。
以下是以前的情况,catch需要一个error参数

// before
try {
  fetch('/')
} catch (error) {
  console.log(error)
}

之后catch中的error是可选的,这对不需要知道抛出的错误是什么的场景可能有些帮助

try {
  fetch('/')
} catch {
  // 处理你的逻辑
}

ES2020(ES11)

ES11增加一些新特性

  • 动态引入
  • BigInt
  • 空值合并运算符
  • 可选链

动态引入

ES6当我们需要引入资源需要在文件开头地方地方使用import,这是一种静态的引入方式。动态引入解决的问题就是可能资源太多包体积太大,有些资源可以通过动态引入的方式进行减少包体积,具体如下:

let stageId = 'A'
let stage

if (stageId === 'A') {
  stage = await import('./stages/A')
} else {
  stage = await import('./stages/B')
}

stage.run();

BigInt

JsNumber类型只能安全的表示-(2^53-1)2^53-1范的值,即Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER,超出这个范围的整数计算或者表示会丢失精度。
创建一个BigInt类型可以使用一下两种方式:

const big = 12344n

const alsoBig = BigInt(20)

控制合并运算符

在获取变量值的时候,通常为了避免为null或未定义,通常需要提供默认值。目前,在JavaScript中表达这种意图的一种典型方法是使用||操作符

const score = null;
console.log(score || 'no-score') // no-score

这对于null或者undefined值的常用情况是可行的,但是存在很多变量并不是null或者undefined,但是取到了一个默认值,如下:

const score = 0;
console.log(score || 'no-score') // no-score

此时打印的结果仍然是no-score,使用ES11的方式就可以避免前面不是undefined或者null但是布尔值是false的情况如下:

const score = 0;
console.log(score ?? 'no-score') // 0

可选链

假如有以下一个对象,属性嵌套很深

const student ={
        profile:{
            school:{
                name:'RUPP'
            }
        }
    }

当我们需要获取这个name属性的时候通常需要向以下的格式进行书写student.profile.school.name,但是如果studentprofile属性不存在,那么就会抛出以下错误:

Uncaught TypeError: Cannot read property 'school' of undefined

所以为了避免这种情况,我们可以通过if条件语句判断一下studentprofile属性是否存在,如果存在才会继续访问内部的属性

if (student.profile && student.profile.school) {
  return student.profile.school.name
}

但是上面这种写法太长了,需要检测对象是否具有某个属性。这种情况就可以使用?.语法来判断对象上是否有该属性,具体使用方式如下:

return student?.profile?.school.name

这就避免了在访问对象属性的时候可能会出现报错的情况

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。