let、const、var三者的区别
- let和const时块级作用域的关键字,var是函数作用域的关键字
- let和const声明的变量不能重复声明,且声明的变量不存在变量提升
- const声明的变量不可修改(对于数组、对象的属性的修改是可以的)
解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量赋值
- 数组的解构
const arr = [1,2,3,4];
let [a,b,c,d] = arr;
console.log(a); //-->1
console.log(b); //-->2
console.log(c); //-->3
console.log(d); //-->4
- 对象的解构
const obj = {
name:"张三",
age:18,
msg:function(){
console.log(123); //ES6支持的简写:msg(){console.log(123)}
}
};
let {name,age,msg} = obj;
console.log(name);
console.log(age);
console.log(msg);
总结:
- 对于对象,针对方法会用的更多一些
- 对象中的方法被频繁调用时,可以利用解构赋值减少代码的重复
rest参数
用于获取函数的实参
function date(...msg){
console.log(msg); //-->[1,2,3]
};
date(1,2,3)
("…"展开运算符:后面js中可用于对数组的浅复制、数组的合并)
数组合并:
const arr = [1,2];
const arr2 = [3,4];
const tog = [...arr,...arr2];
console.log(tog); //-->[1,2,3,4]
Symbol数据类型
表示独一无二的值
特点:
1. 值是唯一的,用来解决命名冲突问题
2. 不能与其他数据进行运算
3. 定义的对象的属性不能用for..in遍历,可以用Reflect.ownKeys获取到对象的所有属性的键名
// 创建symbol
// 方法一
let s = Symbol();
// 方法二
let s2 = Symbol.for();
let s3 = Symbol.for();
// s2 === s3 -->false
给对象添加Symbol类型的属性:
const obj = {
name:"tom",
[Symbol("hello")]:function(){ //添加Symbol类型的方法
console.log(123);
}
};
console.log(obj);
迭代器
for…of遍历
const arr = [1,2,3,4];
for(let i of arr){
console.log(i); //获取到数组的每一个元素
}
工作原理:
数据部署了iterator接口
const iterator = arr[Symbol.iterator]();
console.log(iterator); // 发现next方法
console.log(iterator.next()); //调用next方法
原理:
- 创建一个指针对象,指向当前数据结构的起始位置
- 每次调用next方法指针向后移动,直到只想最后一个成员
- 每次调用next方法返回一个包含value和done属性的对象(done为false代表遍历还没结束,为true代表遍历结束)
原生具备iterator接口的数据(可用for…of遍历):
Array、Arguments、Set、Map、String、TypeArray、NodeList
- 利用迭代器自定义遍历数组:
const obj = {
name: "班级",
stus: [
"p1",
"p2",
"p3"
],
// 需求:遍历obj对象中的数组:stus
[Symbol.iterator]() {
// 创建变量记录索引
let index = 0;
return {
next:() => {
if(index < this.stus.length){
const result = {value:this.stus[index],done:false};
// 索引自增
index++;
return result;
} else {
return {value:undefined,done:true};
}
}
}
console.log(this);
},
};
for(let i of obj){
console.log(i); //-->p1,p2,p3
}
生成器
- 本质是一个函数
- 通过next方法控制代码的向下执行
作用: - 打破完整运行,拥有暂停和启动的能力
- 解决异步操作
语法:
- 函数声明
// 函数名前加*,表示该函数是一个生成器
function * test(){
}
- 只要是可以定义函数的地方,就可以定义生成器
- 箭头函数不能用来定义生成器
- yield表达式
yield作为函数代码的分隔符,也是暂停符
function * test(){
console.log(1);
yield "hello";
console.log(2);
yield "world";
}
let iter = test(); //获取迭代器对象
iter.next(); //通过next方法调用-->1
iter.next(); //通过next方法调用-->2
//遍历yield
for(let i of test()){
console.log(i) // -->hello world
}
- 当调用 next 方法时,开始执行,遇到 yield 表达式,就暂停后面的操作,将 yield 后面的表达式的值,作为返回的对象的 value 值
- 生成器可以传参,next方法也可以传参,next方法的参数作为yield语句的返回结果
function * test(){
console.log("第一次");
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two)
let three = yield 333;
console.log(three);
}
let iter = test("abc");
iter.next(); //第一次调用 -->第一次
iter.next("aaa"); //第二次调用返回值为第一个yield语句
iter.next("bbb"); //第三次调用返回值为第二个yield语句
iter.next("ccc"); //第四次调用返回值为第三个yield语句
- 异步编程的实例1
// 实例需求:1s后输出111 2s后输出222 3s后输出333
function one(){
setTimeout(()=>{
console.log(111);
iter.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iter.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(333);
iter.next();
},3000)
}
// 定义一个生成器
function * gen(){
yield one();
yield two();
yield three();
}
let iter = gen();
iter.next();
- 异步编程的实例2
// 模拟获取: 用户数据 订单数据 商品数据
function user(){
setTimeout(()=>{
let date = "用户数据";
iter.next(date);
},1000)
}
function mait(){
setTimeout(()=>{
let date = "订单数据";
iter.next(date);
},1000)
}
function goods(){
setTimeout(()=>{
let date = "商品数据";
iter.next(date);
},1000)
}
// 定义生成器函数
function * gen(){
let p1 = yield user();
console.log(p1);
let p2 = yield mait();
console.log(p2);
let p3 = yield goods();
console.log(p3);
}
let iter = gen();
iter.next();
promise
是ES6引入的异步编程的新解决方案,语法上promise是一个构造函数用来封装异步操作并可以获取其成功或失败的结果
实例:
const p = new Promise(function(resolve,reject){ //两个参数,1成功 2失败
setTimeout(() => {
// 成功
// let date = "用户数据";
// resolve(date); //调用该函数,p对象的状态会被定义为成功
// 失败
let err = "读取失败";
reject(err); //调用该函数,p对象的状态会被定义为失败
}, 2000);
});
// 调用promise的then方法
p.then(function(value){ //成功时执行(value为参数,指向date的值)
console.log(value);
},function(reason){ //失败时执行(reason为参数,指向date的值)
console.error(reason);
})
- promise对象接收一个函数为参数,该函数接受两个参数(resolve,reject),代表成功和失败
在异步操作中调用这两个函数会把promise对象的状态也定义为成功或失败 - 成功则调用promise对象的then方法(接受两个函数为参数,第一个函数为成功时调用,第二个函数为失败时调用),输出成功或失败的结果。
Set(集合)
ES6 提供的新的数据结构Set。类似于数组,但成员的值都是唯一的,集合具备iterator接口,所以可以使用扩展运算符和[for…of]进行遍历。
- 声明及其一些属性和方法:
// 声明一个set
let s = new Set();
let s2 = new Set(["Tom","Joker","Mary","Rose","Rose"]); //可以接受一个可迭代数据作为参数,会自动去除重复的元素
// 获取元素个数
console.log(s2.size);
// 增加一个元素
console.log(s2.add("Lisa"));
// 删除元素
s2.delete("Joker");
console.log(s2);
// 检查元素
console.log(s2.has("Rose")); // -->boolean
// 清空
s2.clear();
console.log(s2);
Map
Map数据结构,类似于对象,但是键的范围不限于字符串,各种类型的值都可以当作键,Map也实现了iterator接口
// 声明Map
let m = new Map();
// 添加元素
m.set("键名",value);
// value的值可以是任何类型的数据
属性和方法:(与Set基本相似)
- .set() ------- 添加
- .size -----获取元素个数
- .delete() ------ 删除
- .get() ------- 获取元素
- .has() ------ 检查
- .clear() ------- 清空
class – 类
在js的笔记中有定义,并且有面向对象的三大特点:封装、继承、多态。此处不做解释
ES6的数值扩展
- Number.isNaN() ----- 检测一个数值是否为NaN
- Number.parseInt() ---- 字符串转整数
- Number.isInteger() ---- 判断一个数是否为整数
- Math.trunc() ----- 将数字的小数部分抹掉
- Math.sign() ----- 判断一个数是正数还是0还是负数(正数返回1,0返回0,负数返回-1)
对象方法的扩展
- Object.is() ----- 判断两个值是否完全相等
- Object.assign() ----- 合并对象
(两个参数,参1:作为合并后返回的对象;参2:要被合并的对象;若两个对象中的属性名完全一样,参2 对象会被参1对象覆盖掉)
ES6的模块化
模块化是指将一个大的程序文件,拆分成许多的小的文件,然后将小文件组合起来。
优点:
- 防止命名冲突
- 提高代码复用
- 维护性高
模块化语法
模块功能主要由两个命令构成:
- export:命令用于规定模块的对外接口(暴露数据)
- import:用于输入其他模块提供的功能(传入数据)
三种暴露方式:
- 直接在数据前加 export — 分别暴露
// 分别暴露:在要暴露的数据前加export
export let school = "师范学院";
export function tach(){
console.log("可以学习!");
}
- 统一暴露
// 统一暴露
export let school = "师范学院";
export function tach(){
console.log("可以学习!");
}
export {school,tach}
- 默认暴露
// 默认暴露:export default 后可以是任何类型的数据,常用对象
export default {
school:"师范学院",
tach:function(){
console.log("可以学习!");
}
}
导入方式:
- 通用方式
import * as 变量名 from ”要引入模块的js路径“; - 解构赋值形式
import { 要导入的变量名 as 别名 } from ‘路径’;
(可以不写别名:import{变量1,变量2,。。} from “路径”;) - 简便形式(只针对默认暴露)
import 变量 from ”lujing “;