引言

ES 6(于2015年6月正式发布)是JavaScript语言的下一代标准,相对于ES 5(于2011年6月正式发布)新增了一些语法规则和数据结构方法,例如比较典型的Set和Map数据结构和箭头函数等,可以理解成传统JavaScript的升级版,后续还会有ES 7、ES 8版本等。Vue 3发布以来,极力推荐采用ES 6的语法来开发代码,另外本书的实战项目将全部采用ES 6代码。由于移动端操作系统和浏览器兼容性问题的限制,虽然大部分机型原生就支持ES 6语法的JavaScript,但是仍有一部分市场占有率较低的机型无法支持ES 6语法,例如Android系统4.4及以下版本和iOS系统8.4及以下版本。因此,为了项目的健壮性和更强的适配性,会采用Node.js的Babel工具来将ES 6代码转换成兼容性更强的ES 5代码。由于ES 6的语法内容很多,相对复杂,因此本章只会对实战项目中用到的ES 6语法结合ES 5的写法来对比讲解和演示。

1. 变量声明

1. let、var和const

在ES 6语法中,新增了let和const来声明变量,在ES 6之前,ES 5中只有全局作用域和函数作用域,代码如下:

if(true) {
var a = 'Tom'
}
console.log('a',a) // Tom

作用域是一个独立的地盘,让变量不外泄出去,但是上面的代码中的变量a就作为全局作用域外泄了出去,所以此时JavaScript没有区块作用域(或称为块级作用域)的概念。在ES 6中加入区块作用域之后,代码如下:

if(true) {
let a = 'Tom'
}
console.log('a',a) // Uncaught ReferenceError: a is not defined

let和var都可以用来声明变量,但是在ES 6中,有下面一些区别:

  • 使用var声明的变量没有区块的概念,可以跨块访问。

  • 使用let声明的变量只能在区块作用域中访问,不能跨块访问。在相同的作用域下,使用var和let具有相同的效果,建议在ES 6语法中使用let来声明变量,这样可以更加明确该变量所处的作用域。const表示声明常量,一般用于一旦声明就不再修改的值,并且const声明的常量必须经过初始化,代码如下:

const a = 1
a = 2 // Uncaught TypeError: Assignment to constant variable
const b // Uncaught SyntaxError: Missing initializer in const declaration

总结一下,如果在ES 5中习惯了使用var来声明变量,在切换到ES 6时,就需要思考一下变量的用途和类型,选择合适的let和const来使代码更加规范和语义化。

2. 箭头函数

ES 6新增了使用“箭头”(=>)声明函数,代码如下:

let f = v => v
// 等同于
var f = function (v) {
return v
}

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分,当函数的内容只有返回语句时,可以省去大括号和return指令,代码如下:

let f = () => 5
// 等同于
var f = function () { return 5 }
let sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2
}

如果箭头数的内容部分多于一条语句,就要用大括号将它们括起来,并且使用return语句返回,代码如下:

let sum = (num1, num2) => {
let num = 0
return num1 + num2 + num;
}

箭头函数会默认绑定外层的上下文对象this的值,因此在箭头函数中,this的值和外层的this是一样的,不需要使用bind或者call的方法来改变函数中的上下文对象,例如下面的代码:

mounted () {
this.foo = 1
setTimeout(function(){
console.log(this.foo) // 打印出1
}.bind(this),200)
}
//相当于
mounted () {
this.foo = 1
setTimeout(() => {
console.log(this.foo) // 同样打印出1
},200)
}

上面的代码中,在Vue.js的mounted方法中,this指向当前的Vue组件的上下文对象,如果想要在setTimeout的方法中使用this来获取当前Vue组件的上下文对象,那么非箭头函数需要使用bind,箭头函数则不需要。箭头函数是实战项目中使用最多的ES 6语法,所以掌握好其规则和用法是非常重要的。

3. 对象属性和方法的简写

ES 6允许在大括号中直接写入变量和函数,作为对象的属性和方法,这样的书写更加简洁,代码如下:

const foo = 'bar'
const baz = {foo}
// 等同于
const baz = {foo: foo}
console.log(baz) // {foo: "bar"}

const foo = 'bar' const baz = {foo} // 等同于 const baz = {foo: foo} console.log(baz) // {foo: "bar"}

{
name: 'item',
data () {
return {
name:'bar'
}
}
mounted () {
},
methods: {
clearSearch () {
}
}
}
// 相当于
{
name: 'item',
data :function() {
return {
name:'bar'
}
}
mounted :function() {
},
methods: {
clearSearch :function() {
}
}
}

在上面的代码中,展示了采用ES 6语法来创建Vue组件所需的方法和属性,包括name属性、mounted方法、data方法等,是后面实战项目中经常使用的写法。

4. 对象解构

在ES 6中,可以使用解构从数组和对象中提取值并赋给独特的变量,代码如下:

// 数组
const input = [1, 2];
const [first, second] = input;
console.log(first,second) // 1 , 2
// 对象
const o = {
a: "foo",
b: 30,
c: "Johnson"
};
const {a, b, c} = o;
console.log(a,b,c) // foo , 30 , Johnson

在上面的代码中,花括号“{ }”表示被解构的对象,a、b和c表示要将对象中的属性存储到其中的变量中。

2. 模块化

在ES 6版本之前,JavaScript一直没有模块(Module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如Ruby的require、Python的import,甚至就连CSS都有@import,但是JavaScript任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。好在广大的JavaScript程序员自己制定了一些模块加载方案,主要有CommonJS和AMD两种。前者用于Node.js服务器,后者用于浏览器。

1. import和export

随着ES 6的到来,终于原生支持了模块化功能,即import和export,而且实现得相当简单,完全可以取代CommonJS和AMD规范成为浏览器和服务器通用的模块化解决方案。

在ES 6的模块化系统中,一个模块就是一个独立的文件,模块中的对外接口采用export关键字导出,可以将export放在任何变量、函数或类声明的前面,从而将它们暴露给外部代码使用,代码如下:要导出数据,在变量前面加上export关键字:

export var name = "小明";
export let age = 20;
// 上面的写法等价于下面的写法
var name = "小明";
let age = 20;
export {
name:name,
age:age
}
// export对象简写的方式
export {name,age}

要导出函数,需要在函数前面加上export关键字:

export function sum(num1,num2){
return num1 + num2;
}
// 等价于
let sum = function (num1,num2){
return num1 + num2;
}
export sum

所以,如果没有通过export关键字导出,在外部就无法访问该模块的变量或者函数。有时会在代码中看到使用export default,它和export具有同样的作用,都是用来导出对外提供接口的,但是它们之间还有一些区别:

  • export default用于规定模块的默认对外接口,并且一个文件只能有一个export default,而export可以有多个。
  • 通过export方式导出,在导入时要加{ },export default则不需要。在一个模块中可以采用import来导入另一个模块export的内容。导入含有多个export的内容,可以采用对象简写的方式,也是现在使用比较多的方式,代码如下:
//other.js
var name = "小明"
let age = 20
// export对象简写的方式
export {name,age}
//import.js
import {name,age} from "other.js"
console.log(name) // 小明
console.log(age) // 20

导入只有一个export default的内容,代码如下:

//other.js
export default function sum(num1,num2) {
return num1 + num2;
}
//import.js
import sum from "other.js"
console.log(sum(1,1)) // 2

有时也会在代码中看到module.exports的用法,这种用法是从Node.js的CommonJS演化而来的,它其实就相当于:

module.exports = xxx
// 相当于
export xxx

ES 6的模块化方案使得原生JavaScript的“拆分”能力提升了一个大的台阶,几乎成为当下最流行的写法,并且应用在大部分的企业项目中。

3. Promise 和 async/await

1. Promise

Promise是一种适用于异步操作的机制,比传统的回调函数解决方案更合理和更强大。从语法上说,Promise是一个对象,从它可以获取异步操作的结果:成功或失败。在Promise中,有三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,无法被Promise之外的方式改变。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。创建一个Promise对象,代码如下:

var promise = new Promise(function(resolve, reject) {
...
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

在上面的代码中,创建了一个Promise对象,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。这是两个内置函数,resolve函数的作用是将Promise对象的状态变为“成功”,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;reject函数的作用是将Promise对象的状态变为“失败”,在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。当代码中出现错误(Error)时,就会调用catch回调方法,并将错误信息作为参数传递出去。Promise对象实例生成后,可以用then方法分别指定resolved(成功)状态和rejected(失败)状态的回调函数以及catch方法,比如:

promise.then(function(value) {
// success逻辑
}, function(error) {
// failure逻辑
}).catch(function(){
// error逻辑
});

then()方法返回的是一个新的Promise实例(不是原来那个Promise实例)。因此,可以采用链式写法,即then()方法后面再调用另一个then()方法,比如:

getJSON("/1.json").then(function(post) {
return getJSON(post.nextUrl);
}).then(function (data) {
console.log("resolved: ", data);
}, function (err){
console.log("rejected: ", err);
});

下面是一个用Promise对象实现的Ajax操作get方法的例子。

var getJSON = function(url) {
// 返回一个Promise对象
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest(); //创建XMLHttpRequest对象
client.open("GET", url);
client.onreadystatechange = onreadystatechange;
client.responseType = "json"; //设置返回格式为json
client.setRequestHeader("Accept", "application/json");//设置发送格式为json
client.send();//发送
function onreadystatechange() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
});
return promise;
};
getJSON("/data.json").then(function(data) {
console.log(data);
}, function(error) {
console.error(error);
});

了解Promise的基本知识可以便于后续学习使用服务端渲染。当然,Promise的应用场合还是比较多的,如果想要深入了解,可以访问网址:https://developer.mozilla.org/en-US/docs/Web/Java Script/Reference/Global_Objects/Promise,进行系统的学习。

2. async/await

async/await语法在2016年就已经提出来了,属于ES 7中的一个测试标准(目前来看是直接跳过ES 7,列为ES 8的标准了),它主要为了解决下面两个问题:

  • 过多的嵌套回调问题

  • 以Promise为主的链式回调问题

前面讲解过Promise,虽然Promise解决了恐怖的嵌套回调问题,但是解决得并不彻底,过多地使用Promise会引发以then为主的复杂链式调用问题,同样会让代码阅读起来不那么顺畅,而async/await就是它们的救星。

async/await是两个关键字,主要用于解决异步问题,其中async关键字代表后面的函数中有异步操作,await关键字表示等待一个异步方法执行完成。这两个关键字需要结合使用。当函数中有异步操作时,可以在声明时在其前面加一个关键字async,代码如下:

async function myFunc() {
//异步操作
}

使用async声明的函数在被调用时会将返回值转换成一个Promise对象,因此async函数通过return返回的值会进入Promise的resolved状态,成为then方法中回调函数的参数,代码如下:

// myFunc()返回一个Promise对象
async function myFunc() {
return 'hello';
}
// 使用then方法就可以接收到返回值
myFunc().then(value => {
console.log(value); // hello
})

如果不想使用Promise的方式接收myFunc()的返回值,可以使用await关键字更加简洁地获取返回值,代码如下:

async function myFunc() {
return 'hello';
}
let foo = await myFunc(); // hello

await表示等待一个Promise返回,但是await后面的Promise对象不会总是返回resolved状态,如果发生异常,则进入rejected状态,那么整个async异步函数就会中断执行,为了记录错误的位置和编写异常逻辑的代码,需要使用try/catch,代码如下:

try {
let foo = await myFunc(); // hello
}catch(e){
// 错误逻辑
console.log(e)
}

下面举一个例子,在后面的实战项目开发中,经常会用到数据接口请求数据,接口请求一般是异步操作,例如在Vue的mounted方法中请求数据,代码如下:

async mounted () {
// 代码编写自上而下,一行一行,以便于阅读
let resp = await ajax.get('weibo/list')
let top = resp[0]
console.log(top)
}

在上面的代码中,ajax.get()方法会返回一个Promise,采用await进行了接收,并且await必须包含在一个用async声明的函数中。可以看出,在使用了async/await之后,整个代码的逻辑更加清晰,没有了复杂的回调和烦琐的换行。至此,对于实战项目中用到的相关ES 6语法基本讲解完毕,如果想进一步了解ES 6的更多语法知识,可以自行在其官网上学习。

ES6 语言基础的更多相关文章

  1. JavaScript 引入方式 语言规范 语言基础 数据类型 常用方法 数组 if_else 比较运算符 for while 函数 函数的全局变量和局部变量 {Javascript学习}

    Javascript学习 JavaScript概述 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript ...

  2. 《MSSQL2008技术内幕:T-SQL语言基础》读书笔记(下)

    索引: 一.SQL Server的体系结构 二.查询 三.表表达式 四.集合运算 五.透视.逆透视及分组 六.数据修改 七.事务和并发 八.可编程对象 五.透视.逆透视及分组 5.1 透视 所谓透视( ...

  3. 《MSSQL2008技术内幕:T-SQL语言基础》读书笔记(上)

    索引: 一.SQL Server的体系结构 二.查询 三.表表达式 四.集合运算 五.透视.逆透视及分组 六.数据修改 七.事务和并发 八.可编程对象 一.SQL Server体系结构 1.1 数据库 ...

  4. C#语言基础

    第一部分 了解C# C#是微软公司在2000年7月发布的一种全新且简单.安全.面向对象的程序设计语言,是专门为.NET的应用而开发的.体现了当今最新的程序设计技术的功能和精华..NET框架为C#提供了 ...

  5. C语言基础回顾

    第一章 C语言基础 1.  C语言编译过程 预处理:宏替换.条件编译.头文件包含.特殊符号 编译.优化:翻译并优化成等价的中间代码表示或汇编代码 汇编:生成目标文件,及与源程序等效的目标的机器语言代码 ...

  6. 黑马程序员_ C语言基础(二)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 概览 今天基础知识分为以下几点内容(注意:循环.条件语句在此不再赘述):   1.Hello W ...

  7. C#语言基础— 输入与输出

    C#语言基础— 输入与输出 1.1函数的四要素:名称.输入.输出.加工 1.2主函数:输出语句.输入语句: Static viod Main(string[] stgs)//下划线部分可以自己指定 { ...

  8. 【GoLang】GO语言系列--002.GO语言基础

    002.GO语言基础 1 参考资料 1.1 http://www.cnblogs.com/vimsk/archive/2012/11/03/2736179.html 1.2 https://githu ...

  9. R语言基础:数组&列表&向量&矩阵&因子&数据框

    R语言基础:数组和列表 数组(array) 一维数据是向量,二维数据是矩阵,数组是向量和矩阵的直接推广,是由三维或三维以上的数据构成的. 数组函数是array(),语法是:array(dadta, d ...

  10. OC语言基础知识

    OC语言基础知识 一.面向对象 OC语言是面向对象的,c语言是面向过程的,面向对象和面向过程只是解决问题的两种思考方式,面向过程关注的是解决问题涉及的步骤,面向对象关注的是设计能够实现解决问题所需功能 ...

随机推荐

  1. 做Data+AI的长期主义者 | 倒计时2天...

    <数据资产管理白皮书>下载地址: https://www.dtstack.com/resources/1073/?src=bbs <行业指标体系白皮书>下载地址: https: ...

  2. 基于 C# 编写的轻量级工控网关和 SCADA 组态软件

    前言 今天大姚给大家分享一个基于 C# 编写.开源(LGPL-3.0 license)的轻量级工控网关和 SCADA 组态软件:SharpSCADA. 项目介绍 SharpSCADA是一个基于 C# ...

  3. 18-利用GPU训练

    1. 利用GPU训练(方式一) ① GPU训练主要有三部分,网络模型.数据(输入.标注).损失函数,这三部分放到GPU上. import torchvision import torch from t ...

  4. CAE科普!电池仿真的必要性

    在当前高油价与低排放的双重挑战下,新能源汽车以其动力电池驱动的特性成为了低碳环保.节能减排的必然选择.然而,电池系统性能的好坏直接关系到新能源电动汽车的行驶里程和使用便利性,其中充电时间.效率.能量密 ...

  5. Vertx 接入Redis (八)

    项目github地址:https://github.com/fotocj007/VertxWebApi web服务器经典的mysql+redis模式,这里介绍redis的接入. 一:导入gradle ...

  6. AI应用实战课学习总结(6)分类算法分析实战

    大家好,我是Edison. 最近入坑黄佳老师的<AI应用实战课>,记录下我的学习之旅,也算是总结回顾. 今天是我们的第6站,一起了解下分类算法基本概念 以及 通过分类算法辅助疾病诊断的案例 ...

  7. AI编程实战:云开发疯狂助攻,React + Vite 做出 FPS 网页游戏不是梦

    回想起最初接触云开发的那段时间,我出于练手的目的,开发了一款基于 HTML 的简易枪战游戏.当我满怀期待地将其展示给玩家时,没想到却被一句点评当场"点醒"了:这不就是打地鼠的升级版 ...

  8. WPF 不能识别的图标代码

    https://blog.csdn.net/YouyoMei/article/details/86702178?utm_medium=distribute.pc_relevant.none-task- ...

  9. 使用ZLAN8308M串口服务器4G通信功能解决远程智能无线电表方案

    我国目前市场上常见的电表记录方式主要以人工手动抄表和预付费卡为主.在我国经济和住房快速发展下,电能消耗计量管理的实际需求以及人民生活水平的不断的提高,对电能智能化.便捷化管理的要求越来越高,远程电表记 ...

  10. k30s刷入国际rom

    先看看效果图 第一步:先解锁BL这个百度,或者官网有工具http://www.miui.com/unlock第二步:下载国际服ROM官网即可https://en.miui.com/下载国际版的哪个版本 ...