命令行工具
在正式讲解ES6新特性之前,我们需要了解一些命令行工具,在日后的课程中,我们会经常用到命令行
常用命令行工具有两种
CMD
命令行工具PowerShell
命令行工具
CMD命令行
- 打开命令行窗口
- win:左下角开始,找到运行,点击,输入
cmd
,回车 - win:
win+r
快速打开命令行窗口 - mac:command + 空格,输入
terminal
- win:左下角开始,找到运行,点击,输入
- 选择盘符:盘符名加冒号
E:
- 查看盘符及目录下文件与文件夹:
win:dir mac:ls
- 清空命令行信息:
win:cls mac:clear
- 进入文件夹或目录:
cd 文件夹名称
- 返回到上一级目录:
cd ../
- 快速补全目录或文件夹名称:
tab
- 创建文件夹:
mkdir 文件夹名称
- 查看历史输入过的命令:上下按键
PowerShell
- 打开方式
- 在开始位置搜索
PowerShell
打开 - 在对应目录按住
shift
+右键,打开
- 在开始位置搜索
- 其他保持一直
实时效果反馈
1. 如何快速打开CMD
命令行工具:
A win+R
B win+E
C win+P
D win+L
2. CMD
命令行中进入文件夹或目录:
A win+R
B mkdir 文件夹名称
C cd ../
D cd 文件夹名称
答案
1=>A 2=>D
ECMAScript 6 简介
ECMAScript 和 JavaScript 的关系
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现,常场合,这两个词是可以互换的。
名称详解
ECMAScript 6(以下简称 ES6)是 JavaScript 语言的标准,在 2015 年 6 月发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
版本 | 官方名称 | 发布日期 |
---|---|---|
ES1 | ECMAScript 1 | 1997 |
ES2 | ECMAScript 2 | 1998 |
ES3 | ECMAScript 3 | 1999 |
ES4 | ECMAScript 4 | 从未发布过 |
ES5 | ECMAScript 5 | 2009 |
ES5.1 | ECMAScript 5.1 | 2011 |
ES6 | ECMAScript 2015(ECMAScript 6) | 2015 |
ES7 | ECMAScript 2016 | 2016 |
ES8 | ECMAScript 2017 | 2017 |
… | … | … |
因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等
语法提案的批准流程
任何人都可以向标准委员会(又称 TC39 委员会)提案,要求修改语言标准。
一种新的语法从提案到变成正式标准,需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。
- Stage 0 - Strawman(展示阶段)
- Stage 1 - Proposal(征求意见阶段)
- Stage 2 - Draft(草案阶段)
- Stage 3 - Candidate(候选人阶段)
- Stage 4 - Finished(定案阶段)
一个提案只要能进入 Stage 2,就差不多肯定会包括在以后的正式标准里面。ECMAScript 当前的所有提案,可以在 TC39 的官方网站GitHub.com/tc39/ecma262查看。
ES6带来的新特性
let
和const
命令- 变量的解构赋值
- 字符串扩展
- 函数扩展
- 对象扩展
- 数组扩展
- 运算符扩展
- Promise对象
- Class
- Class 继承
- …
Nodejs环境安装
本节课为前置课程,在接下来的ES6课程中,我们需要先安装Nodejs环境
Nodejs简介
Nodejs诞生于2009年,主攻服务器方向,使得利用JavaScript
也可以完成服务器代码的编写
Nodejs安装
Nodejs官网
Nodejs的安装与一般软件一样
大量的库
在安装Nodejs
的同时,会附带一个npm
命令,npm
是Node的包管理工具,这样正是接下来我们要用到的
npm 的简单结构有助于 Node.js 生态系统的激增,现在 npm 仓库托管了超过 1,000,000 个可以自由使用的开源库包
npm
镜像
由于服务器在国外,所以下载速度比较慢,我们可以用国内的镜像
阿里镜像地址
在命令行运行如下命令即可
1 | npm install -g cnpm --registry=https://registry.npmmirror.com |
看到如下信息,代表安装成功
Babel转码器
Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在老版本的浏览器执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持
浏览器支持性查看
Babel官网
转码示例
原始代码用了箭头函数,Babel 将其转为普通函数,就能在不支持箭头函数的 JavaScript 环境执行了
1 | // 转码前 |
Babel安装流程
第一步:安装 Babel
1 | npm install --save-dev @babel/core |
第二步:配置文件.babelrc
Babel 的配置文件是.babelrc,存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。
该文件用来设置转码规则和插件,基本格式如下
1 | { |
第三步:转码规则
presets字段设定转码规则,官方提供以下的规则集,你可以根据需要安装
1 | npm install --save-dev @babel/preset-env |
第四步:将规则加入.babelrc
1 | { |
Babel命令行转码
Babel 提供命令行工具@babel/cli
,用于命令行转码
1 | npm install --save-dev @babel/cli |
基本用法如下
1 | # 转码结果输出到标准输出 |
实时效果反馈
1. Babel的作用是什么:
A Babel是ES6的一部分,是ES6的新特性
B Babel是ES6的转码器,可以将 ES6 代码转为 ES5 代码
C Babel是配置文件,配置ES6环境
D Babel是ES5的基础知识
2. 下列哪个是安装Babel命令转码工具:
A npm install --save-dev @babel/core
B npm install --save-dev @babel/preset-env
C npm install --save-dev @babel/cli
D npx babel example.js
答案
1=>B 2=>C
Let 命令
ES6
新增了let
命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。
let块级作用域
1 | { |
for
循环的计数器,就很合适使用let
命令
1 | for (let i = 0; i < 10; i++) { |
对比var
和let
在循环中的应用
1 | var a = []; |
上面代码,输出的10
,而我们期待的是6
1 | var a = []; |
上面代码,输出的6
let不存在变量提升
var
命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined
。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用
为了纠正这种现象,let
命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
1 | // var 的情况 |
let不允许重复声明
let
不允许在相同作用域内,重复声明同一个变量。
1 | // 报错 |
实时效果反馈
1. 下列那个不是Let的特性:
A Let是块级作用域
B Let不存在变量提升
C Let不允许重复声明
D Let和Var一样并没有区别
答案
1=>D
Const 命令
const
声明一个只读的常量。一旦声明,常量的值就不能改变
1 | const PI = 3.1415; |
const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值
1 | const foo; |
const
的作用域与let命令相同:只在声明所在的块级作用域内有效
1 | if (true) { |
const
命令声明的常量也是不存在提升
1 | if (true) { |
const
声明的常量,也与let
一样不可重复声明
1 | var message = "Hello!"; |
实时效果反馈
1. 下列const
特性描述错误的是:
A const
命令声明的常量不提升
B const
命令不可重复声明
C const
命令是块级作用域
D const
命令声明可以改变
答案
1=>D
对象解构赋值
解构可以用于对象
1 | let {name,age} = {name:"iwen",age:20}; |
温馨提示
对象的属性没有次序,变量必须与属性同名,才能取到正确的值
1 | let {age,name} = {name:"iwen",age:20}; |
1 | let {sex,age,name} = {name:"iwen",age:20}; |
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
1 | let { random,floor } = Math; |
注意事项,如果要将一个已经声明的变量用于解构赋值,必须非常小心
1 | let hello = "Hello"; |
实时效果反馈
1. 下列对象解构赋值的代码,输出结果是多少:
1 | let hello = "Hello"; |
A hello
B Hello
C 报错
D undefined
答案
1=>C
字符串扩展
字符串Unicode 表示法
ES6 加强了对 Unicode 的支持,允许采用\uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。
Unicode
统一码(Unicode),也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
1 | "\u0061" |
字符串遍历器接口
for...of
循环遍历
1 | for (let i of 'itbaizhan') { |
模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
1 | let url = "www.itbaizhan.com" |
实时效果反馈
1. 下列字符串模板,表示正确的是:
A <img src='{url}' alt='{tip}'>
B <img src='${url}' alt='${tip}'>
C <img src='$url' alt='$tip'>
D <img src='url' alt='tip'>
答案
1=>B
字符串新增方法
includes(), startsWith(), endsWith()
传统上,JavaScript 只有indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
- **includes()**:返回布尔值,表示是否找到了参数字符串
- **startsWith()**:返回布尔值,表示参数字符串是否在原字符串的头部
- **endsWith()**:返回布尔值,表示参数字符串是否在原字符串的尾部
1 | let s = 'Hello world!'; |
这三个方法都支持第二个参数,表示开始搜索的位置
1 | let s = 'Hello world!'; |
repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
1 | 'x'.repeat(3) // "xxx" |
padStart(),padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
1 | 'x'.padStart(5, 'ab') // 'ababx' |
trimStart(),trimEnd()
ES2019对字符串实例新增了trimStart()
和trimEnd()
这两个方法。它们的行为与trim()
一致,trimStart()
消除字符串头部的空格,trimEnd()
消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
1 | const s = ' itbaizhan '; |
at()
at()
方法接受一个整数作为参数,返回参数指定位置的字符,支持负索引(即倒数的位置)。
1 | const str = 'hello'; |
温馨提示
如果参数位置超出了字符串范围,
at()
返回undefined
实时效果反馈
1. 下列字符串方法中,那个可以判断是否包含某个字符串:
A includes()
B repeat()
C padStart()
D at()
答案
1=>A
数组扩展_扩展运算符
扩展运算符(spread)是三个点(...
)。将一个数组转为用逗号分隔的参数序列
1 | console.log(...[1, 2, 3]) |
替代函数的 apply 方法
由于扩展运算符可以展开数组,所以不再需要apply
方法,将数组转为函数的参数了
1 | // ES5 的写法 |
合并数组
扩展运算符提供了数组合并的新写法
1 | const arr1 = ['a', 'b']; |
实时效果反馈
1. 下列代码,获取数组的最大值,划横线处填写的代码是:
1 | Math.max(___[14, 3, 77]) |
A apply
B call
C ...
D concat
答案
1=>C
数组扩展_新增方法
Array.from()
Array.from
方法用于将类数组转为真正的数组
温馨提示
常见的类数组有三类:
- arguments
- 元素集合
- 类似数组的对象
arguments
1 | function add(){ |
元素集合
1 | let divs = document.querySelectorAll('div'); |
类似数组的对象
1 | let arrayLike = { |
Array.of()
Array.of()
方法用于将一组值,转换为数组
1 | Array.of(3, 11, 8) // [3,11,8] |
实时效果反馈
1. 下列代码输出结果是什么:
1 | Array.of(3) |
A [3] [3]
B [,,,] [,,,]
C [,,] [3]
D [3] [,,,]
答案
1=>D
对象的扩展
属性的简洁表示法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
1 | let name = "iwen" |
除了属性简写,方法也可以简写
1 | const o = { |
这种写法用于函数的返回值,将会非常方便
1 | function getPoint() { |
属性名表达式
ES6 允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内
1 | let propKey = 'itbaizhan'; |
对象的扩展运算符
ES2018 将这个运算符引入了对象
1 | let z = { a: 3, b: 4 }; |
实时效果反馈
1. 下列代码输出结果是什么:
1 | let propKey = 'itbaizhan'; |
A true
B 报错
C undefined
D propKey
答案
1=>C
函数的扩展_箭头函数
基本用法
ES6 允许使用“箭头”(=>
)定义函数
1 | var add = (x) => x; |
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
1 | var add = (x,y) => x+y; |
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return
语句返回
1 | var add = (x,y) => { |
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
1 | var add = (x,y) => ({x:10,y:20}); |
箭头函数的一个用处是简化回调函数(匿名函数)
1 | var arr = [10,20,30] |
使用注意点
对于普通函数来说,内部的this
指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this
对象,内部的this
就是定义时上层作用域中的this
1 | var name = "itbaizhan" |
温馨提示
箭头函数里面根本没有自己的
this
,而是引用外层的this
实时效果反馈
1. 下列代码运行结果是多少:
1 | var name = "itbaizhan" |
A itbaizhan
B iwen
C null
D 报错
答案
1=>B
Set 数据结构
基本用法
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set
本身是一个构造函数,用来生成 Set 数据结构。
1 | const s = new Set(); |
通过add()
方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。
Set
函数可以接受一个数组作为参数
1 | const set = new Set([1, 2, 3, 4, 4]); |
数组去除重复成员的方法
1 | // 去除数组的重复成员 |
字符串去除重复字符
1 | [...new Set('ababbc')].join('') |
向 Set 加入值的时候,不会发生类型转换,所以5
和"5"
是两个不同的值。
1 | var mySet = new Set(); |
size属性
返回Set
实例的成员总数
1 | const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); |
实时效果反馈
1. 下列代码输出结果是多少:
1 | var mySet = new Set(); |
A "5" 5 5
B "5" 5
C "5"
D null
答案
1=>B
Set 数据结构方法
add()
set
添加方法
1 | var mySet = new Set(); |
delete()
删除某个值,返回一个布尔值,表示删除是否
1 | var mySet = new Set(); |
has()
返回一个布尔值,表示该值是否为Set
的成员
1 | var mySet = new Set(); |
clear()
清除所有成员,没有返回值
1 | var mySet = new Set(); |
实时效果反馈
1. 下列那个方法可以清空Set
数据结构中所有的数据:
A add()
B delete()
C has()
D clear()
答案
1=>D
Promise 对象
基本概念
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise
对象
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理
有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易
基本用法
ES6 规定,Promise
对象是一个构造函数,用来生成Promise
实例
1 | const promise = new Promise(function(resolve, reject) { |
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署
Promise
实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数。
1 | promise.then(function(value) { |
加载图片资源例子
1 |
|
实时效果反馈
1. Promise
的作用是什么,下列描述正确的是:
A Promise
是异步编程的一种解决方案,可以将异步操作以同步操作的流程表达出来
B Promise
是同步编程的一种解决方案,可以将同步操作以异步操作的流程表达出来
C Promise
使得控制同步操作更加容易
D Promise
还不是ES6的标准,目前是社区版本
答案
1=>A
Promise对象_Ajax实操
Promise封装Ajax,让网络请求的异步操作变得更简单
1 |
|
Async 函数
ES2017 标准引入了 async 函数,使得异步操作变得更加方便
async函数可以将异步操作变为同步操作
示例代码
1 | function print(){ |
基本语法
1 | function timeout(ms) { |
异步应用
1 | function ajax(url){ |
实时效果反馈
1. Async
是什么:
A Async是完成网络请求,如Ajax一样
B Async的作用是完成异步网络请求,如Ajax一样
C Async使得异步操作变得更加方便
D Async是新的网络请求解决方案
答案
1=>C
Class 的基本语法
类的由来
JavaScript 语言中,生成实例对象的传统方法是通过构造函数
1 | function Point(x, y) { |
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class
关键字,可以定义类
基本上,ES6 的class
可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
1 | class Point { |
constructor 方法
constructor()
方法是类的默认方法,通过new
命令生成对象实例时,自动调用该方法。一个类必须有constructor()
方法,如果没有显式定义,一个空的constructor()
方法会被默认添加
1 | class Point { |
类的实例
生成类的实例的写法,与 ES5 完全一样,也是使用new
命令
1 | class Point { |
注意点
不存在提升
类不存在变量提升(hoist),这一点与 ES5 完全不同
1 | new Foo(); // ReferenceError |
实时效果反馈
1. 下列代码,划横线处要填写的代码时:
1 | class Person { |
A ""
B new
C this
D class
答案
1=>B
Class属性与方法
实例方法
通过类的实例对象调用方法
1 | class People{ |
实例属性
实例属性指的是类的实例对象可调用的属性
1 | class People{ |
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static
关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”
1 | class Person { |
温馨提示
注意,如果静态方法包含
this
关键字,这个this
指的是类,而不是实例。
1 | class People { |
静态属性
静态属性指的是 Class 本身的属性,即Class.propName
1 | class People{} |
实时效果反馈
1. 下列代码,运行结果是什么:
1 | class People { |
A hello
B world
C null
D undefined
答案
1=>A
Class 的继承
基础用法
Class 可以通过extends
关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多
1 | class Point { |
ES6 规定,子类必须在constructor()
方法中调用super()
,否则就会报错,这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。如果不调用super()
方法,子类就得不到自己的this
对象
1 | class Point { |
Module 的语法
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require
、Python 的import
,甚至就连 CSS 都有@import
,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍
ES6 模块是通过export
命令显式指定输出的代码,再通过import
命令输入。
1 | export var Hello = "hello" // hello.js文件 |
测试方式
我们采用Nodejs方式进行测试Module语法
但是nodejs采用的是CommonJS的模块化规范,使用require引入模块;而import是ES6的模块化规范关键字。想要使用import,必须引入babel转义支持,通过babel进行编译,使其变成node的模块化代码。
疑惑:为啥不用前端方式测试,前端方式测试会更加麻烦
第一步:全局安装babel-cli npm install -g babel-cli
第二步:安装 babel-preset-env npm install -D babel-preset-env
第三步:运行代码 babel-node --presets env index.js
export 命令
export命令导出变量
1 | export var firstName = 'sxt'; |
export命令导出函数
1 | export function add(x, y) { |
import 命令
使用export
命令定义了模块的对外接口以后,其他 JS 文件就可以通过import
命令加载这个模块
1 | // name.js |
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名
1 | // value.js |
除了指定加载某个输出值,还可以使用整体加载,即用星号(*
)指定一个对象,所有输出值都加载在这个对象上面
1 | // circle.js |
export default 命令
从前面的例子可以看出,使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default
命令,为模块指定默认输出。
1 | // export-default.js |
其他模块加载该模块时,import
命令可以为该匿名函数指定任意名字
1 | // import-default.js |
实时效果反馈
1. 下列那个不属于ES6的Module语法的关键字:
A export
B import
C export default
D require
答案
1=>D