项目中常用的 ES6 新特性总结

目录

1.ES的兼容性

 2.let 和 const 命令

3.类 Class

4.函数参数默认值 

5.箭头函数

6.模板字符串

7.变量的解构赋值

8.扩展运算符(spread)

9.模块化 Module

10.对象属性简写

11.Promise

12.for...of



1.ES的兼容性

一定要明白,即便 ES2015 到 ES2019 已经发布,也不是所有的浏览器都支持新特性。为了 获得更好的体验,最好使用你选择的浏览器的最新版本。 通过以下链接,你可以检查在各个浏览器中哪些特性可用。

  •  ES2015(ES6):http://kangax.github.io/compat-table/es6/
  • ES2016+:http://kangax.github.io/compat-table/es2016plus/

根据上面链接中的兼容性表格来看,它的大部分功能在现代浏览器中都可以使用。即使有些 ES2016+的特性尚未支持,但是我们还是可以开始使用新语法和新功能了。

 2.let 和 const 命令

在ES6以前,js只有var一种声明方式,在ES6之后 新增 let 和 const两种方式。var 定义的变量没有块级作用域的概念,let和const声明的都有块级作用域。

  • let 的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
  • const声明的是一个只读的常量。一旦声明,常量的值就不能改变。
{
  let a = 1;
  var b = 1;
  const c = 3;
}

// let const 的块级作用域
a // ReferenceError: a is not defined.
b // 1
c // ReferenceError: a is not defined.

// const 声明的常量不能重复赋值,let可以
const d = 4
let e = 5
d = 6    //  Assignment to constant variable.
e = 7
e    // 7

let、const和var的区别:在 变量提升、全局变量、重复声明、重复赋值、暂时死区、块级作用域、只声明不初始化功能的区别

var不会块级作用域,和暂时死区,其他都可以。

let 块级作用域,可重复赋值但是不能 变量提升、全局变量、重复声明。

const 只有暂时死区和块级作用域,其他都不可以。在声明的时候就必须赋值。

3.类 Class

在ES6之前,生成实例对象的传统方法是通过构造函数。如下:

function Book(name, page){
    this.name = name;    // 书名
    this.page = page;    // 页数
}
Person.prototype.getBookInfo = function () {
    return 'Book is ' + this.name + ', it is ' + this.page
}
var myBook = new Book('js',35)

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。所以在ES6之后,上面的代码可以简化为:

class Book {
  constructor(name, page){
    this.name = name;
    this.page = page;
  }

  getBookInfo() {
    return 'Book is ' + this.name + ', it is ' + this.page
  }
}

4.函数参数默认值 

ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。像这样:

function changeName(name){
    var my_name = name || 'xiao'
    console.log(my_name)
}

changeName('lisa')    // lisa
changeName('')    // xiao
changeName()    // xiao

上面代码检查函数changeName的参数name有没有赋值,如果没有,则指定默认值为xiao。这种写法的缺点在于,如果参数name赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数name等于空字符,结果被改为默认值。

在ES6里面,这个问题就可以解决:

function changeName(name = 'xiao'){
    console.log(my_name)
}

changeName('lisa')    // lisa
changeName('')    // ''
changeName()    // xiao

5.箭头函数

ES6 允许使用“箭头”(=>)定义函数。箭头函数表达式的语法比函数表达式更简洁。在ES6前后的函数定义变化:

let fn = function (name) { 
  return name
};
// es6里面
let fn = name => name;

相比之间是不是简介很多呢,而且如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分 像这样:

let fn = () => 'haha';
// es6之前是这样
let fn = function () { return 'haha' };

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。如果箭头函数只有一行语句,且不需要返回值,可以采用下面的写法,就不用写大括号了。

let fn = () => console.log('haha');

使用箭头函数需要注意:

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

尤其注意箭头函数里面的this的指向是可变的,但是在箭头函数的内部,this的指向是固定。

6.模板字符串

传统的 JavaScript 语言,拼接语句和输出模板通常是这样写的:

let name = 'javascript', money = 35
let str = 'This is '+name+',it is '+money+' dollar'

console.log(str)    // "This is javascript,it is 35 dollar"

在ES6里面就方便了许多,可以这样写:

let name = 'javascript', money = 35
let str = `This is ${name},it is ${money} dollar`

console.log(str)    // "This is javascript,it is 35 dollar"

7.变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。在ES6之前,为变量赋值只能这样:

let a = 1;
let b = 2;
let c = 3;

在ES6里面,就可以这样简写:

let [a, b, c] = [1, 2, 3];

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。只要等号两边的模式相同,左边的变量就会被赋予对应的值。是不是简洁了许多呢。

8.扩展运算符(spread)

扩展运算符(spread)是三个点(...),将数组表达式或者string在语法层面展开该运算符主要用于函数调用、数组构造的时候。

console.log(...[1,2,3])    // 1 2 3

在ES6之前我们想要对数组进行操作,类似于数组元素求和这种功能,我们需要这样写:

var arr = [1,2,3]
function sum (x, y, z){
    return x+y+z
}
var total = sum.apply(this,arr)    // 改变this的指向,否则计算会有误
console.log(total); // 6

在ES6里面,我们可以这样写:

var total_1 = sum(...arr)
console.log(total_1); // 6

相比之前的写法,就省事很多。由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。但是要注意的是扩展运算符只能用于可迭代对象数组或是string。

[...'str']    // ["s", "t", "r"]

9.模块化 Module

在ES6之前,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。只有社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。比如,CommonJS 模块就是对象,输入时必须查找对象属性。

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上面的代码狮子就是整体加载fs模块(就是fs的所有方法),生成一个对象_fs,然后再从这个对象上面读取start、exists、readfile这三个方法。只有在运行的时候才能得到这个对象,导致完全没办法在编译时做“静态优化”。

在ES6的模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。这样我们就可以按需引入我们需要的模块,可以实现在编译时做“静态优化”

// ES6模块
import { stat, exists, readFile } from 'fs';

以上这种写法,实质上只是从fs模块中按需只加载3个方法,其他的方法就不用加载出来。这也叫做静态加载。即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。

10.对象属性简写

在ES6之前,假设我们需要将某个变量值直接赋值给同样名称的对象属性时,我们是这样写的:

var name = 'xiao'
var sex = '女'
var obj = { name: name, sex: age }

在ES6中可以这样简写:

var name = 'xiao'
var sex = '女'
var obj = { name, sex }

11.Promise

Promise 是异步编程的一种解决方案。简单说它就像是一个容器,里面放着某个在未来才会执行结束的事件(一般是一个异步操作)的结果。它有三种状态:

  • pending(进行中)
  • fulfilled(已成功)
  • rejected(已失败)

只有异步操作的结果,可以决定当前是哪一种状态,其他的任何其他操作都无法改变这个状态,因为对象的状态不受外界的影响。而且状态一旦改变就不会再变(一旦状态变为 resolved 后,就不能再次改变),任何时候都会得到这个结果。以下是Promise的一个简单的示例:

const promise= new Promise((resolve, reject) => {
    resolve('success')
    // 以下无效
    reject('reject')
})
promise.then(val => {
    console.log('ok')  // ok
}, err => {
    console.log('err')
})

注意:当我们构造Promise的时候,构造函数内部大代码都是立即执行的。像这样

const promise= new Promise((resolve, reject) => {
    console.log('promise')
    resolve('success')
})

console.log('finish')

promise.then(val => {
   console.log('ok') // ok
}, err => {
   console.log('err')
})

// promise => finish => ok

Promise 实现了链式调用,也就是在每一次调用then 的时候都会返回一个Promise,并且是一个全新的promise,因为Promise的状态是不可变的。如果你在then中使用了return 那么return 的值也会被 Promise.resolve 包装。像这样:

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

而且在ES6之前我们使用ajax的异步请求的时候就会存在ajax内部嵌套ajax,像下面这样,有了 permise 之后就可以改写为较简洁的书写方式,如下所示:

ajax(url, () =>{
    ajax(url_1, () =>{
         ajax(url_2, () =>{

         })
    })
})

// 可改写成
ajax(url).then(res => {
    console.log(res)
    return ajax(url_1)
}).then(res => {
    console.log(res);
    return ajax(url_2)
}).then(res => console.log(res))

12.for...of

在ES6中 借鉴 C++、Java、C# 和 Python 语言,引入了for...of循环,作为遍历所有数据结构的统一的方法。

for... of 循环可以使用的范围包括数组 Array、Set和Map结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)以及字符串String等等。在迭代对象上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

例如:

const arr = ['red', 'green', 'blue']
for(const item of arr){
    console.log('item',item);
}
// item red
// item green
// item blue

for...of循环可以代替数组实例的forEach方法。例如:

arr.forEach(item => {
    console.log('item',item);
});
// item red
// item green
// item blue

运算结果是一样的,JavaScript原有的 for...in 循环,只能获得对象的键名,不能直接获取到键值,如下。在ES6中 提供 for...of 循环,允许遍历取得键值。

for(const item in arr){
    console.log('item',item);
}
// item 0
// item 1
// item 2

 

在持续更新中...

 

你可能感兴趣的:(JScript)