ES6
ES6(ECMAScript2015)即ECMAScript的2015年颁布的标准,新标准内容主要是js的语法糖,方便开发者更好的编写js,使开发更加工程性
变量
变量声明
ES5使用var的声明变量,具有3个特点
- 可以重复声明
- 没有块级作用域
- 不能限制修改
因此,ES6为让变量更可控制,完善了声明变量
let
- 声明的变量名不允许重复声明(同一作用域下)
- let声明变量支持块级作用域
const
- 声明常量,不可被修改
- 常量声明时必须初始化
- 具备let所有特性
注:
块级作用域:即语法块(花括号内),每次执行括号内,变量都在独立的作用域中
预解析:let,const声明的变量不会被预解析
解构赋值
数组的解构赋值
let [a,b,c] = [1,2,3]; //1,2,3
一个变量数组 = 一个值数组,以逗号分隔后相互对应项赋值;支持设置默认值;
对象的解构赋值
let {a,b,c} = {a:1,b:2,c:3}; //1,2,3
变量对象 = 变量值对象,不存在声明顺序问题;支持变量新别名对值接收
允许使用默认值
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
var {x, y = 5} = {x: 1};
其他用法
let { cos,sin,random } = Math; //func,func,func;将对象值赋予环境变量
let [a,b,c,d,e,f] = "hello"; //h,e,l,l,o,undefined解构字符串
import { data, request } from 'request' //解构引入模块的成员
函数
参数默认值
function getNum(outNum = 0){//支持对函数形参赋予默认值
return outNum;
};
箭头函数
写法简洁
let getSum = (a,b) => console.log(a + b);
// 一个参数可省去括号,一行代码可省去花括号
this指向
var obj = {show: () => console.log(this);}
doucment.onclick = obj.show;
箭头函数特点:
- this指向:是定义时所在的对象,而不是使用时所在的对象。
- 由于其this特殊性,不允许使用 new 操作符使其提升为构造函数
- 没有默认的 arguments 对象
字符串
方法
includes(str,index)
判断字符串是否包含参数指定字符串,index为起始检索位
startsWith(str)
判断字符串是否以参数指定字符串开头
endsWith(str)
判断字符串是否以参数指定字符串结束
模板字符串
ES5
var data = {name: 'page',age: '20'};
var html = '<p>姓名:'+ data.name +'</p><p>年龄'+ data.age +'</p>';
ES6
let html = `
<p>姓名:${data.name}</p>
<p>年龄:${data.age}</p>`;
拓展运算符
使用 ...
rest参数(剩余参数转成数组)
function test(multiNum,...numbers){//独立参转为数组
return multiNum * numbers.reduce(function(prev,next,index,arr){
return prev * next
})
};
延伸
let arr = [2,2,3];
console.log(test(...arr));//将数组拓展,把数组项转为多个独立参数
let arr2 = [4,4,5];
console.log([...arr,...arr2]); //将两个数组拆分后并至一个数组
// 箭头函数内不支持访问arguments参数对象,可通过拓展运算符实现
let getOPtions = (...arguments) => console.log(arguments);
对象
let data = {person: {name: 'page',age: 20, gender: '男'...}};
let res = {...data}; // 快速浅拷贝
let info = {...data.person}; // 拷贝部分
对象
增强写法
const app = {
height,
width,
render(options){ ... }
}
属性名表达式:对象声明的属性是环境下变量值
es5
var str = 'collected';
var type = {};
type[str] = true;
es6
var str = 'collected';
var type = {[str]: true};
Class类
ES5:创建类使用构造函数,给构造函数prototype添加方法
ES6:class关键字声明类,constructor声明构造函数,内部声明原型方法
class dropdown{
static defaults = { options : true } // 静态属性/方法
loaded = "loaded" // 声明实例默认属性(公开字段声明)
constructor ($ele,options){ // 构造函数
this.$ele = $ele;
this.options = options;
}
// 原型方法
show(){
this.$ele.showHide("show");
}
hide(){
this.$ele.showHide("hide");
}
get value(){
return "value"
}
set value(val){
this._value = val;
}
// 私有属性/方法
#privateAttr = "value";
#getPrivateAttr(){
return this.#privateAttr;
}
};
class继承
class Dog extends Animals {
constructor(name,type){
super(name); //调用父类构造函数
}
// 原型方法自动继承父类原型
};
class类的特点:
- 内部定义的所有方法不可枚举,如constructor,getName,getColor
- 类必须使用new调用,不能如es5中构造函数可单独调用
- 类声明不会预解析提升,原因是类的继承必须保证子类在父类之后定义。
Promise
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。可以理解为承诺将异步返回结果传递给关联处理程序,实现编写类似同步的代码进行异步操作;
状态
-
pending 待定的初始状态
-
fullfilled 操作成功
-
rejected 操作失败
resolve与reject
const preloadImage = function (path) {
const image = new Image();
image.onload = resolve;
return new Promise(function (resolve, reject) {
image.onerror = reject;
image.src = path;
});
};
preloadImage('/images/eg.png').then(
() => console.log('success'), // 作为参数resolve回调函数
() => console.log('failed') // 作为参数reject回调函数
)
Primise.all
注意
- Promise内部会在创建时立马执行,resolve/reject并不会阻塞代码执行
- resolve/reject回调仅会在循环队列,即不会马上执行
手写Promise
异步操作回调 => Promise实例记录 => 执行对应then回调
class Ipromise {
constructor(asycback){
this.status = 'pending'; // 初始状态
this.value = undefined; // fullfilled结果
this.result = undefined; // rejected结果
this.fullfilledCallbacks = []; // fullfilled状态下回调集合
this.rejectedCallbacks = []; // rejected状态下回调集合
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
try{
asycback(this.resolve,this.reject); // 代理执行,完成后更新状态
}catch(e){this.reject(e)}
}
reject(result){
if(this.status === 'pending'){
this.status = 'rejected';
this.result = result;
this.rejectedCallbacks.forEach(function(callback){
callback(result);
})
}
}
resolve(store){
if(this.status === 'pending'){
this.status = 'fullfilled';
this.value = store;
this.fullfilledCallbacks.forEach(function(callback){
callback(store);
})
}
}
then(fullfilled,rejected){
switch(this.status){
case 'pending' :
this.fullfilledCallbacks.push(fullfilled);
this.rejectedCallbacks.push(rejected);
break;
case 'fullfilled': fullfilled(this.store);
break;
case 'rejected': rejected(this.result);
break;
}
}
}
new Ipromise(function(resolve,reject){
setTimeout(function(){
resolve(2)
},2000);
}).then(
function(data){console.log(data)},
function(error){console.log(error)},
)
数组
Array.from(list,mapFn)
- 将类数组(Nodelist等)与可遍历对象转为Array类型
- mapFn为转数组前对数组项的处理
Array.of(item...)
- 将一组值转化为数组
- es5我们常用[].slice.call(arguments)
Array.find/findIndex(func,func的this指向对象)
- 返回满足查找条件的第一个索引项/索引
- 未找到返回undefined/-1
for快速遍历
循环索引值
for(let index in this.list){
console.log(i + ': ' + this.list[i]);
};
循环数组项
for(let item of this.list){
console.log('数组项: ' + item)
};
兼容ES6
es6大部分新特性需要IE10+,兼容低版本浏览器时可使用babel编译为es5代码
Babel
初始化npm
npm i init
安装babel编译器,bebel cli命令工具,babel编译相关参数
npm i @babel/core @babel/cli @babel/preset-env
新建.babelrcl配置文件
{
"presets": [
"@babel/env",
"@babel/preset-react"
],
"plugins": []
}
执行编译输出命令
babel src -d dist // 将src目录的js编译至dist目录下
polyfill
问题
Babel默认只转换新的JavaScript语法(语法糖),并不会转换API(如:Symbol、Promise),以及全局对象上的方法,如Object.assign
解决:自动补丁
安装
npm install --save @babel/polyfill
项目根目录创建babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1",
},
"useBuiltIns": "usage",
"corejs": "3.6.5",
}
]
]
}
Symbol类型
symbol是一种基本数据类型。Symbol()函数会返回symbol类型的值,一个symbol值能作为对象属性的标识符。这意味着对象属性类型包括字符串属性和Symbol标识的属性两种;
创建
let id = Symbol();
let info = Symbol('info'); //参数仅是对该symbol的描述
使用
let obj = {
[id]: 2020, //使用symbol标识唯一属性,声明需以方括号包裹
id: '2020', //普通的字符串属性'id'
};
访问symbol属性,必须通过symbol访问
console.log(obj[id],obj.id); //2020,'2020'
Object.getOwnPropertySymbols(obj)
- 返回symbol属性组成的数组,用于遍历symbol属性
Set对象
与Array相同,Set对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。
let s = new Set();
let sets = new Set([0,{},[1,2],'a str']);
s.add(0);
sets.has(-1); //flase
sets.size(); //length
set.delete(0);
数组去重
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]);
支持foreach遍历
Map对象
Map对象保存键值对,允许任何值(对象或者原始值) 都可以作为一个键或一个值(映射),并且能够记住键的原始插入顺序。
let myMap = new Map([[2,'two'],[3,'three']]);
myMap.set(0, "zero");
myMap.set(1, "one");
for (let [key, value] of myMap) {
console.log(key + " = " + value);
}
async/await函数
以同步写法编写异步处理,比Promise更简洁,与Promise密切相关
返回Promsie
async function foo() {
return 1; // 等同于return Promise.resolve(1)
}.then(res => console.log(res));
await
async function foo() { // await终止函数内执行,后续代码被放在then回调
await 1; // Promise.resolve(1).then(
await 2; // reuturn Promise.resolve(2)
} // )
Proxy代理器
Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
创建
const p = new Proxy(target, handler) //返回一个代理器
// target为代理的对象实例,handle对象即所有代理操作
// 对代理器的操作自动handler
Module模块
相对已有的CommonJS、AMD模块化规范,新增ES6 Module(按引用传递)
export
基本使用
export var num = 0;
export const Temp = 'xx';
export function func() {};
// 等同于
export { num, Temp, func }
// 继承
export * from './module1.js';
export * from './module2.js';
export default
// func模块
// export default唯一性, 但支持与具名导出并存
export default function func() {}
// 引用
import func from './func.js';
as关键字
const value = 'xxx';
export {
value as outName
...
}
export { default as AppMain } from './AppMain';
// 或
export { default } from './xxx.js';
import
基本使用
import './script.js';
import { num } from './xxx.js';
// 注意:num应该作为只读,由于按引用传值,修改是危险操作
num++; // warn dangerous
as关键字
import { vaule as A } from './xxx.js';
import * as api from './api.js';
import default
import module1, { childModule1 } from "./main.js";
运行时加载
// 与require相像
import('./xx.js');
if(true) import('./xx.js');
import(getModulePath(params));
// promise
import('./xx.js').then(({export1, export2}) => console.log('imported!'));
new Promise.all([import('./module1.js'), import('./module2.js')]);