ES6(ECMAScript)
新的一年过去小半了,赶紧学起来,不做前端懒狗!!!!
新特性
声明变量
let const
- 变量不能重复声明
- 块级作用域
- 不存在变量提升,但是有暂时性死区
- 不影响作用域链
- const 声明常量,一旦被声明,无法被修改(但如果是存储对象可以修改对象的属性值)
- 不会污染全局变量,不会挂载到 window 上
模板字符串
插入变量时使用${}
参数带默认值的函数
function add(a = 10, b = 20) {
return a + b;
}
// 默认的表达式也可以是个函数
function add1(a = 10, b = getVal(5)) {
return a + b;
}
function getVal(val) {
return val;
}
剩余参数,剩余运算符(rest)...
function add(...arg) {
// arg是一个数组,获取所有参数
}
扩展运算符(spread)...
const maxNum = Math.max(20, 30); //maxNum = 20;
// ES5中
const arr = [10, 20, 30, 40, 50];
let arrNum = Math.max.apply(null, arr);
//ES6中
arrNum = Math.max(...arr);
箭头函数
// 以下两种写法等价
let add = function () {};
let add = () => {};
// ES5中this指向取决于调用该函数的上下文对象
// ES6箭头函数有this指向,箭头函数内部this值通过查找作用域链
// 箭头函数内部没有arguments
// 箭头函数不能使用new关键字来实例化对象
解构赋值
对对象解构
let person = {
name: "Aniss",
gender: "female",
};
//完全解构
let { name, gender } = person;
console.log(name, gender); //Aniss female
//不完全结构
// let {name} = person;
// console.log(name); //Aniss
// 剩余运算符
// let {name,...res} = person;
// console.log(res); //{gender: 'female'}
对数组解构
let arr = [1, 2, 3];
let [a, b] = arr;
console.log(a, b); //1 2
扩展的对象功能
ES6 直接写入变量和函数,作为对象的属性和方法
let name = "Aniss";
let gender = "female";
let person = {
// ES5 ↓
// name:name,
// gender:gender,
// ES6 ↓
name,
gender,
};
let name = "Aniss";
const obj = {
isShow: true,
[name + "name"]: "AA",
["a" + name]() {
console.log(this);
},
};
对象的方法
// is() === 比较两个值是否严格相等
console.log(NaN === NaN); //false; === 不能判断所有一致的值是否相等
console.log(Object.is(NaN, NaN)); //true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); //false
//assign()对象的合并
//Object.assign(target,obj1,obj2,……) 将后面的对象属性合并到target上,是浅拷贝
let obj = Object.assign({}, { name: "Aniss" }, { gender: "female" });
//obj = {name:'Aniss',gender:'female'}
原始数据类型 Symbol
表示独一无二的值 用来定义对象的私有变量
let name1 = Symbol("name");
let name2 = Symbol("name");
console.log(name1 === name2); //false
// 如果用Symbol定义的对象中的变量一定要用[]的形式存取
let obj = {};
obj[name1] = "Aniss";
// 等价于
let obj = { [name1]: "Aniss" };
console.log(obj[name1]); // Aniss
// 使用Symbol定义的对象中属性无法被for循环和Object.keys遍历
// 1、可以使用Object.getOwnPropertySymbols方法
let keys = Object.getOwnPropertySymbols(obj);
console.log(keys[0] === name1); // true;
// 2、使用Reflext.ownKeys(obj);
let keys1 = Reflect.ownKeys(obj);
console.log(keys1[0] === name1); // true;遍历所有属性,包括普通和Symbol类型的
Set 集合
表示无重复值的有序列表
let set1 = new Set();
console.log(set1);
// Set(0) {size: 0}
// size表示集合的大小
// 添加元素
set1.add(2);
set1.add("4");
// 删除某个值
set1.delete(2);
// 校验某个值是否在set中
set1.has("4");
// 获取set的大小
set1.size;
// forEach循环,键和值相等
set1.forEach((val, key) => {
console.log(val, key);
});
// 将set转换成数组
let set2 = new Set([1, 2, 3, 4, 5, 6, 6, 6, 7]);
let arr = [...set2];
console.log(arr); //获取不重复的数组
// set中对象的引用无法被释放
let set3 = new Set();
let obj = {};
set3.add(obj);
// 对象释放当前资源
obj = null;
console.log(set3); // {}仍被存储在set中
// WeakSet类型可以释放对象的引用
// 1、不能传入非对象类型的参数
// 2、不可迭代
// 3、没有forEach
// 4、没有size属性
Map 类型
是键值对的有序列表。键和值是任意类型
// 以下两种命名方式等价
let map = new Map();
map.set("name", "Aniss");
map.set("gender", "female");
let map1 = new Map([
["name", "Aniss"],
["gender", "female"],
]);
console.log(map);
// Map(2) {'name' => 'Aniss', 'gender' => 'female'}
// 获取map的属性值
map.get("name");
// 校验是否含有某个属性
map.has("name");
// 删除某个属性
map.delete("name");
// 清除map的所有属性
map.clear();
//WeakMap
数组的扩展功能
from() 将伪数组转换成真正的数组
function add() {
// console.log(arguments); arguments是伪数组
// es5转换
// let arr = [].slice.call(arguments)
// es6写法
let arr = Array.from(arguments);
// from还可以接收第二个参数,用来对每个元素进行处理
// 也可以通过扩展运算符将伪数组转换成真正的数组
// let arr = [...arguments];
}
of() 将任意数据类型的一组值转换成数组
console.log(Array.of(1, 33, "ddf", [1, 2, 3], { a: "fjdhgfv" }));
copywithin() 数组内部将指定位置的元素复制到其他的位置,返回当前数组
[1, 2, 3, 8, 9, 10].copyWithin(0, 3);
// [8,9,10,8,9,10]
find() findIndex()
find()找出第一个符合条件的数组成员 findIndex()找出第一个符合条件的数组成员的索引
let num = [1,2,-10,-20,9,2].find(n=>n<0);
let numIndex = [1,2,-10,-20,9,2].findIndex(n=>n<0);
// num:-10
// numIndex:2
entries() keys() values()返回一个遍历器,可以用 for...of 循环进行
for (let index of ["a", "b"].keys()) {
console.log(index);
}
// 0 1
for (let ele of ["a", "b"].values()) {
console.log(ele);
// a b
}
for (let [index, ele] of ["a", "b"].entries()) {
console.log(index, ele);
// 0:a 1:b
}
// 遍历器next方法
let it = ["a", "b"].entries();
console.log(it.next().value); // 0:a
console.log(it.next().value); // 1:b
includes()返回一个布尔值,表示某个数组是否包含给定的值
console.log([1, 2, 3].includes(2)); // true
迭代器 Iterator
是一种新的遍历机制 1、迭代器是一个接口,能快捷访问数据,通过 Symbol.iterator 来创建迭代器,通过 next 方法获取迭代后的结果 2、迭代器是用于遍历数据结构的指针
const items = ["one", "two", "three"];
const ite = items[Symbol.iterator]();
console.log(ite.next()); // {value: 'one', done: false} done为false表示便利继续,true为完成遍历
generator 函数
可以通过关键字,将函数挂起,为了改变执行流提供了可能,同时为了做异步编程提供了方案 和普通函数的区别:
- function 关键字后面 函数名之前有个*
- 只能在函数内部使用 yield 表达式,让函数挂起
function* func(params) {
console.log("start");
yield 2;
yield parmas;
}
// 只是返回一个遍历器对象,不打印 可以继续调用next();
let fn = func(3);
console.log(fn.next()); // start {value: 2, done: false}
console.log(fn.next()); // {value: 3, done: false}
console.log(fn.next()); // {value: undefined, done: true}
//generator函数是分段执行的,yield语句是暂停执行,next()恢复执行
function* add() {
console.log("start");
let x = yield "2";
console.log("one:" + x);
let y = yield "3";
console.log("two:" + y);
return x + y;
}
const fn = add();
console.log(fn.next()); // start {value: 2, done: false}
console.log(fn.next(20)); // one:20 {value: 3, done: false}
console.log(fn.next(30)); // two:30 {value: 50, done: true}
console.log(fn.next()); //{value: undefined, done: true}
//使用场景:为不具备Interator接口的对象提供了遍历操作
function* objextEntries(obj) {
const keys = Object.keys(obj);
for (const k of keys) {
yield [k, obj[k]];
}
}
const obj = {
name: "Aniss",
age: 18,
};
obj[Symbol.iterator] = objextEntries;
console.log(obj); //{name: 'Aniss', age: 18, Symbol(Symbol.iterator): ƒ}
for (let [key, value] of objextEntries(obj)) {
console.log(`${key}:${value}`);
}
generator 的应用
// 回调地狱
$.ajax({
url: "", // 接口请求地址
method: "get",
success(res) {
console.log(res);
// 继续发送请求
…………
},
});
function* main(){
let res = yield request('');// 接口请求地址
console.log(res)
// 执行后面的操作
console.log("数据请求完成,可以继续操作")// 接口请求完,才会打印这句话
}
const ite = main();
ite.next()
function request(url){
$.ajax({
url, // 接口请求地址
method: "get",
success(res) {
ite.next(res)
},
});
}
// 加载页面
function* load() {
loadUI();
yield getData();
hideLoad();
}
let itLoad = load();
itLoad.next();
function loadUI() {
console.log("加载loading页面");
}
function getData() {
setTimeout(() => {
console.log("获取页面数据");
itLoad.next();
}, 1000);
}
function hideLoad() {
console.log("隐藏loading页面");
}
Promise
async 异步操作
使得异步操作更加方便
function getData1() {} //异步操作
function getData2() {} //异步操作
// async会返回一个Promise对象
// 是Generator的语法糖
async function fn() {
// await "Aniss"; //await会把这个字符串转换成Promise对象
let a1 = await getData1(); // await保证所有操作按照书写顺序执行
let a2 = await getData2();
return { a1, a2 };
}
// then会等待所有的await指令运行完再执行
fn()
.then((res) => {
console.log(res);
})
.catch((e) => {});
async function fn2() {
// await Promise.reject("出错了"); // 只要有一个出错,后面的就不会执行,直接返回错误的对象
try {
await Promise.reject("出错了"); //这样就不会报错
} catch (e) {}
await Promise.resolve("成功了");
}
fn2()
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
Class 类
class Person {
// 实例化的时候会被立即调用
constructor(name, age) {
this.name = name;
this.age = age;
}
getName() {
return this.name;
}
getAge() {
return this.age;
}
}
Object.assign(Person.prototype, {
setName(name) {
this.name = name;
},
});
let Aniss = new Person("Aniss", 18);
console.log(Aniss);
类的继承使用关键字 extends
class Person {
// 实例化的时候会被立即调用
constructor(name, age) {
this.name = name;
this.age = age;
}
getName() {
return this.name;
}
getAge() {
return this.age;
}
}
class Young extends Person {
constructor(name, age, color) {
super(name, age); //Person.call(this,name,age)
this.color = color;
}
getColor() {
return this.color;
}
// 重写父类的方法
getAge() {
return `${this.name}永远18`;
}
}
let Aniss = new Young("Aniss", 18, "pink");
console.log(Aniss.getName()); //Aniss
console.log(Aniss.getAge()); //Aniss永远18