ES6
ES6是JavaScript的下一个版本标准,与ES5版本(目前浏览器确定支持)相比引入了一些新特性
JS基础笔记见: JS
Demo代码:ES6demo.zip
TBA: 异步、await的mdn文档尚未看完
常用功能
声明&块作用域
| 声明 | 作用域 |
|---|---|
| var | 全局;变量 |
| let | 块作用域内;变量 |
| const | 块作用域内;常量 const a = 'a' 不可修改 a = 'c' const obj = {a:'a'} 可修改 obj.a = 'c' |
块作用域{}示例:
{
// var myNum = 8
// let myNum = 8
// const myNum = 8
}
console.log(myNum) // let,const 块作用域外不能访问
- 使用var声明变量时可能会失手覆盖/修改,使用let/const声明可以限制其作用域
- var变量相当于挂载成window的属性,
window.globalVar可查看; - 由于var变量是属性,所以可以在作用域内多次声明而不报错(let会有SyntaxError)
- 当引用发生在声明前,var、let都会提升声明至作用域顶部,但不会提升初始化赋值,故而let报错(而var是window的属性,会有初始值undefined):
console.log(a) // undefined
var a = 10
console.log(a) // 10
console.log(b) // Reference Error
let b = 10
console.log(b) // 10
模板字符串
使用反引号`${}`,反引号内支持换行
const str1 = 'abc'
const str2 = `def
${str1}
`
console.log(str2)
解构赋值
可以很方便地将数据赋给常量/变量,简化代码;
数组依次赋值,...restVar表示余下的值都丢给restVar
const [a,b,c,...restVar] = [1,2,3,4,5,6]
console.log(a,b,c,restVar) // 1,2,3,[4,5,6]
obj需要对应数据内的属性名称,但可以通过oldVar:newVar来重新命名
const {user,No:Number,...restInfo} = {
user: 'U1',
No: '001',
depart: 'D1',
site: 'SH'
}
console.log(user,Number,restInfo)
扩展(...)
数组
arr1 = [1,2,3]
arr2 = [4,5,6]
arr3 = [...arr1,...arr2,7,8,9]
console.log(arr3)
对象
obj1 = {a:1}
obj2 = {b:2}
obj3 = {
c:3,
...obj1,
...obj2
}
console.log(obj3)
伪数组
伪数组具备数组的一些功能(长度,下标访问..)但不具备方法(forEach,push..);
例如:伪数组arguments表示当前传入function的所有实参,需要Array.from(arguments)实现forEach方法(push之类的虽然不报错但也没用)
function fn () {
console.log(arguments)
//arguments.forEach( (item) => {console.log(item)}) // 伪数组,不能执行
Array.from(arguments).forEach( (item) => {console.log(item)})
}
fn(1,2,3)
Object浅拷贝
- 浅拷贝:共用一个内存地址,对象的变化相互影响
- 深拷贝:将新对象放到新的内存中,对象的变化不会相互影响
下例中,将objA,objB,objC的feature全合给{}后赋予objAll;如果存在同名属性,则后面的属性会覆盖前面的属性。(?)
objAll = Object.assign({},objA,objB,objC)
注意,当属性为简单数据类型时(string/number..),其实进行了深拷贝
objA = {a:1}
objB = {b:2}
objC = {c:3}
objAll = Object.assign({},objA,objB,objC)
objA.a = 100
console.log(objAll) // still 1
当属性为引用类型时(Object..),进行的是浅拷贝
objA = {a:{Aa:1}}
objB = {b:2}
objC = {c:3}
objAll = Object.assign({},objA,objB,objC)
objA.a.Aa = 100
console.log(objAll) // changed to 100
Class
要素:constructor,自定义函数,继承,override
class A {
constructor (var1,var2) {
this.var1 = var1
this.var2 = var2
}
logVar1() {
console.log(this.var1)
}
logVarAll() {
console.log(this.var1,this.var2)
}
}
class B extends A {
constructor (var1,var2,var3){
super(var1,var2)
this.var3 = var3
}
logVarAll() {
console.log(this.var1,this.var2,this.var3)
}
}
const b1 = new B('aa','bb','cc')
b1.logVar1() //'aa'
b1.logVarAll() //'aa','bb','cc'
箭头函数
可以简化function的写法或匿名方程;左侧输入、右侧输出/步骤
() => {alert('empty func')}
(n) => {return 2n+1}
n => 2n+1
const arrFunRes = n => 2n+1
arrFunRes(2) //5
异步(TBA)
JS中先执行完同步任务后再执行异步任务队列。常见的异步:Timer,Ajax
本例主要是为了确保成功执行的顺序,i.e.事件B要在事件A成功后才能执行
Promise
- Promise.reject(): 返回一个已拒绝(rejected)的 Promise 对象
- Promise.resolve(): 将给定的值转换为一个 Promise。如果该值是一个 thenable 对象,将调用其 then() 方法;否则,返回的 Promise 将会以该值兑现。
- Promise.prototype.then(): 用于 Promise 兑现和拒绝情况的回调函数
- Promise.prototype.catch(): 用于注册一个在 promise 被拒绝时调用的函数
简单使用
function onSucc () {console.log('Succ')}
function onFail () {console.log('Fail')}
const p1 = Promise.resolve() // 'Succ' 'Succ' 'Succ' - 'Succ' 不推荐catch后再加then
.then(onSucc).then(onSucc).then(onSucc).catch(onFail).then(onSucc)
const p2 = Promise.reject() // - - - 'Fail' 'Succ' 不推荐catch后再加then
.then(onSucc).then(onSucc).then(onSucc).catch(onFail).then(onSucc)
Promise.resolve()相当于
const p1 = new Promise((resolve,reject)=>{
resolve()
}).then(...).catch(...)
模拟resolve/resolve轮流进行的情况,适合使用 then(onSucc,onFail) 而不是 catch(onFail) ---- catch 适合放在结尾,但是为何同样是加在 catch后,p1 正常但 p2 会出现 UnhandledPromiseRejection?
function onSucc () {
console.log('Succ')
return Promise.reject()
}
function onFail () {
console.log('Fail')
return Promise.resolve()
}
// - - - 'Fail' 'Succ' 'Fail'
const p1 = Promise.reject().then(onSucc).then(onSucc).then(onSucc).catch(onFail).then(onSucc).catch(onFail)
// 'Fail' 'Succ' 'Fail' 'Succ'+UnhandledPromiseRejection
const p2 = Promise.reject().then(onSucc,onFail).then(onSucc,onFail).catch(onFail).then(onSucc)
当 Promise 处于 pending状态时,不能参与计算,可以使用 .all() 或者等待其一先完成
const slowNum = async (time,val) => {
return new Promise(
(resolve, reject) => {resolve(val)},
time
)
}
const A = slowNum(3000,1)
const B = slowNum(1000,2)
// Not working: [object Promise][object Promise]
console.log( A + B)
// Ok: get 3
console.log( await A + await B)
// Ok: get 3
Promise.all([A,B]).then( ([valA,valB]) => {console.log( valA + valB)} )
// Ok: get 3 --- nested
A.then((valA) => {
B.then( (valB) => {console.log( valA + valB)} )
}
)
Async
异步处理的语法糖,无需刻意地链式调用 promise。
function asyncTask () {
console.log('Doing asyncTask')
setTimeout(() => {console.log('Finish asyncTask')}, 2000)
}
async function asyncMain () {
console.log('Start asyncMain')
asyncTask() //await asyncTask() doesn't waiting!!
asyncTask() //await asyncTask() doesn't waiting!!
console.log('End asyncMain')
}
p1 = asyncMain() //p1是Promise对象
//Start asyncMain
//Doing asyncTask
//Doing asyncTask
//End asyncMain
//Finish asyncTask
//Finish asyncTask
await
await用于等待一个异步操作完成后再运行余下代码
// 1.准备一个返回Promise对象的函数
function asyncTask (ms) {
console.log('Doing asyncTask' + ms)
return new Promise((resolve) => {setTimeout(() => {resolve('Succ asyncTask' + ms)}, ms)})
}
// 2. async + await
async function asyncMain () {
console.log('Start asyncMain')
console.log(await asyncTask(6000))
console.log(await asyncTask(1000))
console.log('End asyncMain')
}
asyncMain()
//Start asyncMain
//Doing asyncTask6000
//Succ asyncTask6000
//Doing asyncTask1000
//Succ asyncTask1000
//End asyncMain
Proxy
当某个值需要伴随着另一个值更新时;Proxy(target,handler),target必须是object
const handler = {
get: function (obj, prop){return obj[prop]},
set: function (obj, prop, val){obj[prop]=val}
}
const myobj = {a:'a'}
const p1 = new Proxy(myobj, handler)
console.log(p1.a) //a
p1.a = 'b'
console.log(myobj.a) //b
myobj.a = 'c'
console.log(p1.a) //c
Module
当代码多的时候,把一些一块儿用的方程或者变量放在同一个js文件里,其它
ESM
- 适用于浏览器
M1.js中:
export const str1 = 'M1'
export function FuncM1 () {
console.log('FuncM1')
}
export default { //default 只能导出一种
name: 'M1 Name'
}
随后在另一个js文件中import、使用它们;例如,ES6demo.js中:
import module1 from './M1.js' //module1就是default,即'M1 Name'
import {str1,FuncM1} from './M1.js'
console.log(xxxDefault)
对于import module的js文件,html中其script标签需要加上 type="module"
<script src="./ES6demo.js" type="module"></script>
需要设置浏览器允许跨域请求,可能报错:(原因:CORS 请求不是 http)。
CommonJS
- 适用于Node.js
M2.js中:
module.exports = {
a:1,
b:2
}
const moduleM2 = require('./M2')
console.log(moduleM2)
随后命令行运行
node .\ES6demo.js
# { a: 1, b: 2 }