这节课我们来学习ES6的一些新特性
变量和常量
ES6可以书写一个代码块表示一个独立的作用域,let变量只在块域中有效,也就是局部变量。可以将代码进行有效分割,也可以避免一个变量名在多个地方使用造成冲突。我们建议局部变量都用let定义。
常量则用const定义(es6之前没有const,常量用全大写字母表示)。
{
let count = 0
count++
const BASE_URL = 'https://api.example.com'
}
严格检查模式
我们知道js对变量的检查并没有很严格,就算不写var或者let声明,直接给一个变量赋值,也不会报错,甚至会设置为全局变量。如果引入了多个js文件,里面设置了同名全局变量,肯定会出错呀。那么如何避免出错呢?在es6中,为了避免变量设置混乱,我们建议局部变量都使用let来声明,其次可以使用严格检查模式,也就是在js文件第一行写一个"ues strict",这样如果变量设置得不对,浏览器就会报错。
<script>
"use strict"
i = 0
console.log(i)
</script>
模板字符串
在js入门1中提到过了,使用反引号,${}引用
const str1 = 'abc'
const str2 = `def${str1}
这也是字符串的内容`
console.log(str2) // "def abc\n这也是字符串的内容"
map和set
在es6中可以使用map和set,用法与java类似。map可以储存键值对(二维数组),set(一维数组)无序不重复。如果要遍历,使用for of。
// map
var map = new Map([['tom', 100], ['jerry', 90], ['lily', 80]]); // 初始化,二维数组
var name = map.get('tom'); // 通过key获取value
console.log(name); // 100
map.set('jack', 70); // 新增或修改
map.delete('jerry'); // 删除
for(let x of map) { // 遍历
console.log(x);
}
// set
var set = new Set([1, 2, 3, 1, 1]); // 初始化,一维数组,set可以去重
set.add(4); // 新增
set.delete(2); // 删除
console.log(set); // Set(3) {1, 3, 4}
set.has(1); // 判断是否存在 true
for(let x of set) { // 遍历
console.log(x);
}
解构赋值
我们给数组或对象里的元素赋值时需要一个个赋值,很麻烦,es6提供了一种简写的赋值方法,可以迅速完成赋值操作
// 数组可以进行解构赋值
const [a, b, c] = [1, 2, 3]
console.log(a, b, c)
// 对象也可以进行解构赋值,也可以修改变量名和设置剩余项
const { username, age: userAge, ...otherInfo } = {
username: '显子',
age: 25,
gender: 'famale',
catrgory: 'user'
}
console.log(username, userAge, otherInfo) // "显子" 25 { gender: "famale", catrgory: "user" }
数组和对象的拓展
拓展运算符
如果想给把旧数组的数值快速赋值给新数组,可以使用拓展运算符...,同时也适用于对象,但是一般会先写新对象本身的属性,把复制的功能放在最后面。
// 1. 扩展运算符
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [0, ...arr1, ...arr2, 7, 8, 9]
console.log(arr3) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
const obj1 = {
a: 1
}
const obj2 = {
b: 2
}
const obj3 = {
name: '显子',
...obj1,
...obj2
}
console.log(obj3) // { name: '显子', a: 1, b: 2 }
数组方法
伪数组无法使用数组的方法,使用Array.from()函数可以使伪数组拥有数组的方法
function fn() {
Array.from(arguments).forEach(function (item) {
console.log(item)
})
fn(1, 2, 3)
}
对象方法
我们也可以使用object.assign()做对象的浅拷贝和功能的合并
const objA = {
name: '显子',
age: 25
}
const objB = {
gender: 'famale'
}
const objC = Object.assign({}, objA, objB)
console.log(objA, objB, objC) // { name: '显子', age: 25 } { gender: 'famale' } { name: '显子', age: 25, gender: 'famale' }
Class
一些语法糖,使js更接近传统的面向对象语法
class A { // 定义类
constructor(name, age) {
this.name = name
this.age = age
}
introduce() {
console.log(`我的名字是${this.name}, 我的年龄是${this.age}`)
}
}
const a1 = new A('显子', 25) // 对象
console.log(a1) // A { name: '显子', age: 25 }
a1.introduce() // 我的名字是显子, 我的年龄是25
class B extends A { // 继承
constructor(name, age, gender) {
super(name, age)
this.gender = gender
}
sayHello() {
console.log('你好我是' + this.name)
}
}
const b1 = new B('小明', 18, '男')
console.log(b1) // B { name: '小明', age: 18, gender: '男' }
b1.sayHello() // 你好我是小明
b1.introduce() // 我的名字是小明, 我的年龄是18
箭头函数
简写的函数,参数 => 返回值,其中比较复杂的返回值也可以用大括号,但要加return
const getSum1 = n => n + 3
const getSum2 = (n, m, ...other) => console.log(n, m, other)
getSum2(1, 2, 3, 4, 5) // 1 2 [3, 4, 5]
const getResult = arr => {
let sum = 0
arr.forEach(item => sum += item)
return sum
}
console.log(getResult([1, 2, 3, 4, 5])) // 15
Promise Async 异步处理
首先我们来理解一下什么是同步和异步。同步就是收到请求后立即执行,中间按无需等待;异步就是收到请求后过一会再执行,会在同步任务都执行完后再触发。比如console.log()就是同步,setTimeout()就属于异步。
console.log('任务1...同步')
console.log('任务2...同步')
setTimeout(() => {
console.log('任务3...异步')
})
console.log('任务4...同步')
// 实际执行顺序是1,2,4,3
如果任务4需要根据任务3的结果来执行,这怎么办呢?比较简单的情况是把任务4加入timeout,放在任务3 的后面,但是如果任务4后面又有异步任务该怎么办呢?这时候就要用到promise了。promise可以将复杂的嵌套异步结构书写为类似于同步的结构,方便阅读。
// promise会标记设计的代码功能中的异步任务的处理结果,并将通过回调返还到p1
const p1 = new Promise((resolve, reject) => { // 两个参数:成功和失败
// resolve('任务1成功得到的数据') // 表示成功,会触发then里的data
reject('任务1失败的信息1') // 表示失败,会触发then里的err,如果找不到就会触发catch
})
p1.then(data => {
console.log(data)
// 如果后续还有异步任务,就写在return后面
// 这个return会被作为p1.then的返回值,并作为下一个then的参数
return new Promise((resolve, reject) => {
// resolve('任务2成功得到的数据')
})
}, err => {
console.log('任务1失败了')
// 如果希望后续都失败,返回一个新的promise或者抛出异常
throw new Error('任务1失败了')
})
.then(data => {
console.log(data)
// 如果后续还有异步任务,就写在return后面
// 这个return会被作为p1.then.then的返回值
return new Promise((resolve, reject) => {
resolve('任务3成功得到的数据')
})
}, err => {
console.log('任务2失败了')
})
// 由于上面的每个then都写了err,可以分别处理每个任务失败的情况,所以不会触发catch
.catch(err => {
console.log(err)
})
async其实是用来进行异步处理的语法糖,可以简化但不能完全替代promise,将异步的格式几乎完全变成同步
// Async
// 步骤1:准备一个返回promise对象的函数
function asyncTask() {
return new Promise((resolve, reject) => {
// 假装有一些关键代码
const isSuccess = true
if (isSuccess) {
resolve('任务2成功的处理结果')
} else {
resolve('任务2失败的处理结果')
}
})
}
// 步骤2:未使用await的函数添加async
async function main() {
console.log('任务1')
const data = await asyncTask()
console.log(data)
console.log('任务3')
}
main() // 输出:任务1 任务2成功的处理结果 任务3
Proxy 代理对象
有个情境:当频繁数据变更时,如何在页面上更新?这时候就可以通过代理的方式来处理
// 如果变更一次数据就更新一次显然是不可行的,会有很多冗余代码
const obj = { name: '显子', age: 25 }
const container = document.getElementById('container')
container.textContent = obj.name //更新页面 显子
obj.name = '小明'
container.textContent = obj.name // 更新页面 小明
对代理对象做修改时,每一次不仅会修改原始数据本身,还会执行在set中设置的功能
const obj = { name: '显子', age: 25 }
const container = document.getElementById('container')
const p1 = new Proxy(obj, { // 配置项,属性的获取设置删除
get(target, property, receiver) {
return obj[property]
},
set(target, property, value) {
obj[property] = value
container.textContent = obj.name //更新页面 显子
}
})
p1.name = 'rose' // 更新数据和页面 rose
Module 模块
把不同类型的功能放到不同的文件里面,就称为模块,分为EMS和CommonJS(只能在node.js中使用)
export const aTitle = 'a模块的标题'
// 导出单个函数
export function aFn() {
console.log('a模块的方法')
}
// 默认导出
export default {
name: 'a模块'
}
// 导出单个属性或函数
export const bTitle = 'b模块的标题'
export function bFn() {
console.log('b模块的方法')
}
// 默认导出
export default {
name: 'b模块'
}
// ESM 需要在script标签中设置type="module"
// 导入模块的默认导出
import moudleA from './a.js'
import moudleB from './b.js'
// 导出模块的某个属性或函数
import { aTitle, aFn } from './a.js'
import { bTitle, bFn } from './b.js'
console.log(moudleA) // { name: 'a模块' }
console.log(moudleB) // { name: 'b模块' }
console.log(aTitle, aFn, bTitle, bFn) // a模块的标题 function aFn() {...} b模块的标题 function bFn() {...}
module.exports = {
a: 1,
b: 2,
c: 3
}
// 等价于
exports.a = 1
exports.b = 2
exports.c = 3
//CommonJS 不能在浏览器运行
const moudleC = require('./c') // 不用写后缀,默认.js
console.log(moudleC) // { a: 1, b: 2, c: 3 }