文章目录
- 📚迭代器
- 🐇定义
- 🐇工作原理
- 🐇自定义遍历数据
- 📚生成器函数
- 🐇声明和调用
- 🐇生成器函数的参数传递
- 🐇生成器函数案例
- 📚Promise
- 📚Set
- 🐇Set的定义与使用
- 🐇集合实践
- 📚Map
- 📚class类
- 📚数值扩展
- 📚对象方法扩展
- 📚ES6模块化
- 🐇模块导出数据语法
- 🐇模块导入数据语法
学习链接:尚硅谷Web前端ES6教程
📚迭代器
🐇定义
- 遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
- ES6 创造了一种新的遍历命令
for...of
循环,Iterator 接口主要供for...of
使用。 - 原生具备 iterator 接口的数据(可用for of 遍历):
Array
、Arguments
、Set
、Map
、String
、TypedArray
、NodeList
。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>迭代器</title> </head> <body> <script> //使用next()方法遍历原生自带iterator接口的数据 // 遍历 Map const mp = new Map(); mp.set('a', 1); mp.set('b', 2); mp.set('c', 3); let iter1 = mp[Symbol.iterator](); console.log(iter1.next()); console.log(iter1.next()); console.log(iter1.next()); console.log(iter1.next()); // 遍历数组 let xiyou = ['唐僧','孙悟空','猪八戒','沙僧']; let iter2 = xiyou[Symbol.iterator](); console.log(iter2.next()); console.log(iter2.next()); console.log(iter2.next()); console.log(iter2.next()); //实际上直接使用 for...of 方法遍历即可 const mp2 = new Map(); mp2.set('a', 1); mp2.set('b', 2); mp2.set('c', 3); for (let [k, v] of mp) { console.log(k, v); } </script> </body> </html>
🐇工作原理
- 创建一个指针对象,指向当前数据结构的起始位置。
- 第一次调用对象的
next
方法,指针自动指向数据结构的第一个成员。 - 接下来不断调用`next方法,指针一直往后移动,直到指向最后一个成员。
- 每调用
next
方法返回一个包含value
和done
属性的对象。 - 应用场景:需要自定义遍历数据的时候,要想到迭代器。
🐇自定义遍历数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义遍历数据</title>
</head>
<body>
<script>
// 需求:遍历对象中的数组
const youyi = {
uname: '右一',
course: [ '可视化', '信息检索', '大数据安全', '类脑' ],
// 通过自定义 [Symbol.iterator]() 方法
[Symbol.iterator]() {
// 初始指针对象指向数组第一个
let index = 0;
// 保存 youyi 的 this 值
let _this = this;
return {
next: function () {
// 不断调用 next 方法,直到指向最后一个成员
if (index < _this.course.length) {
return { value: _this.course[index++], done: false };
} else {
// 每调用next 方法返回一个包含value 和done 属性的对象
return { value: undefined, done: true };
}
}
}
}
}
// for...of直接遍历达到目的
for (let v of youyi) {
console.log(v);
}
</script>
</body>
</html>
📚生成器函数
🐇声明和调用
- 生成器函数是 ES6 提供的一种 异步编程解决方案,语法行为与传统函数完全不同。
*
的位置没有限制- 使用
function * gen()
和yield
可以声明一个生成器函数。生成器函数返回的结果是迭代器对象,调用迭代器对象的next
方法可以得到yield
语句后的值。 - 每一个
yield
相当于函数的暂停标记,也可以认为是一个分隔符,每调用一次next()
,生成器函数就往下执行一段。 next
方法可以传递实参,作为yield
语句的返回值。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器</title> </head> <body> <script> //生成器其实就是一个特殊的函数 //函数代码的分隔符 function * gen(){ console.log(111); yield '一只没有耳朵'; console.log(222); yield '一只没有尾部'; console.log(333); yield '真奇怪'; console.log(444); } let iterator = gen(); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); // 遍历 for(let v of gen()){ console.log(v); } </script> </body> </html>
- 使用
🐇生成器函数的参数传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生成器函数参数</title>
</head>
<body>
<script>
function* generator(arg) {
console.log(arg); // 生成器第 1 段
let one = yield 111;
console.log(one); // 生成器第 2 段
let two = yield 222;
console.log(two); // 生成器第 3 段
let three = yield 333;
console.log(three); // 生成器第 4 段
}
let iter = generator('aaa'); // 传给生成器第 1 段
console.log(iter.next());
console.log(iter.next('bbb')); // 传给生成器第 2 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ccc')); // 传给生成器第 3 段,作为这一段开始的 yield 语句返回值
console.log(iter.next('ddd')); // 传给生成器第 4 段,作为这一段开始的 yield 语句返回值
</script>
</body>
</html>
🐇生成器函数案例
- 需求:1s 后控制台输出 111 2s后输出 222 3s后输出 333。
- 传统方式:嵌套太多,代码复杂
setTimeout(() => { console.log(111); setTimeout(() => { console.log(222); setTimeout(() => { console.log(333); }, 3000); }, 2000); }, 1000);
- 生成器实现:结构简洁明了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生成器函数实例</title> </head> <body> <script> function one(){ setTimeout(()=>{ console.log(111); iterator.next(); },1000) } function two(){ setTimeout(()=>{ console.log(222); iterator.next(); },2000) } function three(){ setTimeout(()=>{ console.log(333); iterator.next(); },3000) } function * gen(){ yield one(); yield two(); yield three(); } //调用生成器函数 let iterator = gen(); iterator.next(); </script> </body> </html>
📚Promise
以下简单过一下 Promise,更多还要进一步深入学习,后续补充。
-
Promise的定义和使用
- Promise 是 ES6 引入的异步编程的新解决方案。
- 语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
- 一个 Promise 必然处于以下几种状态之一:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功完成。
- 已拒绝(rejected):意味着操作失败。
- Promise 的使用:
- Promise 构造函数:
new Promise((resolve, reject)=>{})
Promise.prototype.then
方法:该方法用于指定当前Promise对象状态改变时的回调函数。它接收两个参数,第一个参数是状态改变为Fulfilled时的回调函数,第二个参数(可选)是状态改变为Rejected时的回调函数。当Promise对象的状态已经是Fulfilled时调用then方法,回调函数会立即执行。Promise.prototype.catch
方法:该方法用于指定当前Promise对象状态变为Rejected时的回调函数。它和then方法的用法类似,但只接收一个参数,即状态变为Rejected时的回调函数。如果Promise对象的状态已经是Rejected,再调用catch方法时,回调函数会立即执行。catch方法返回一个新的Promise对象,可以链式调用后续的then方法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Promise基本语法</title> </head> <body> <script> //实例化 Promise 对象 const p = new Promise(function(resolve, reject){ // 使用 setTimeout 模拟请求数据库数据操作 setTimeout(function(){ // 这个异步请求数据库数据操作是否正确返回数据 let isRight = true; if (isRight) { let data = '数据库中的数据'; // 设置 Promise 对象的状态为操作成功 resolve(data); } else { let err = '数据读取失败!' // 设置 Promise 对象的状态为操作失败 reject(err); } }, 1000); }); //调用 promise 对象的 then 方法 p.then(function(value){ console.log(value); }, function(reason){ console.error(reason); }) </script> </body> </html>
- Promise 构造函数:
-
Promise封装读取文件
//1. 引入 fs 模块 const fs = require('fs'); //2. 调用方法读取文件 // fs.readFile('./resources/为学.md', (err, data)=>{ // //如果失败, 则抛出错误 // if(err) throw err; // //如果没有出错, 则输出内容 // console.log(data.toString()); // }); //3. 使用 Promise 封装 const p = new Promise(function(resolve, reject){ fs.readFile("./resources/为学.md", (err, data)=>{ //判断如果失败 if(err) reject(err); //如果成功 resolve(data); }); }); p.then(function(value){ console.log(value.toString()); }, function(reason){ console.log("读取失败!!"); });
📚Set
🐇Set的定义与使用
- ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of』进行遍历。
- 定义一个 Set 集合:
let st1 = new Set(); let st2 = new Set([可迭代对象]);
- 集合(这里假设有一个集合 st)的属性和方法:
st.size
:返回集合个数st.add(item)
:往集合中添加一个新元素 item,返回当前集合st.delete(item)
:删除集合中的元素,返回 boolean 值st.has(item)
:检测集合中是否包含某个元素,返回 boolean 值st.clear()
:清空集合- 集合转为数组:
[...st]
- 合并两个集合:
[...st1, ...st2]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>集合</title> </head> <body> <script> //声明一个 set let s = new Set(); let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']); //元素个数 console.log(s2.size); //添加新的元素 s2.add('喜事儿'); //删除元素 s2.delete('坏事儿'); //检测 console.log(s2.has('糟心事')); for(let v of s2){ console.log(v); } //清空 s2.clear(); console.log(s2); </script> </body> </html>
🐇集合实践
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Set 实践</title>
</head>
<body>
<script>
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
let result = [...new Set(arr)];
console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result2);
//3. 并集
let union = [...new Set([...arr, ...arr2])];
console.log(union);
//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
</script>
</body>
</html>
📚Map
- ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是 “键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of』进行遍历。
- 定义一个map
let mp1 = new Map(); mp1.set('aaa', 111); mp1.set('bbb', 222); mp1.set('ccc', 333); let mp2 = new Map([ ['aaa', 111], ['bbb', 222], ['ccc', 333] ]); console.log(mp1['aaa']); // 111 console.log(mp2.get('bbb')); // 222
- Map 的属性和方法:(k 为键,v为值)
size
:返回 Map 的元素(键值对)个数。set(k, v)
:增加一个键值对,返回当前 Map。get(k)
:返回键值对的键值。has()
:检测 Map 中是否包含某个元素。clear()
:清空集合,返回 undefined。
📚class类
- ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
- function构造函数的继承
//手机 function Phone(brand, price){ this.brand = brand; this.price = price; } Phone.prototype.call = function(){ console.log("我可以打电话"); } //智能手机 function SmartPhone(brand, price, color, size){ Phone.call(this, brand, price); this.color = color; this.size = size; } //设置子级构造函数的原型 SmartPhone.prototype = new Phone; // 矫正 constructor 指向 SmartPhone.prototype.constructor = SmartPhone; //声明子类的方法 SmartPhone.prototype.photo = function(){ console.log("我可以拍照") } SmartPhone.prototype.playGame = function(){ console.log("我可以玩游戏"); } const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch'); console.log(chuizi);
- extends类继承和方法的重写
- ES6 中直接使用 extends 语法糖(更简洁高级的实现方式)来实现继承,同时可以重写父类的方法,直接在子类中重新写一次要重写的方法即可覆盖父类方法。
class Phone{ //构造方法 constructor(brand, price){ this.brand = brand; this.price = price; } //父类的成员属性 call(){ console.log("我可以打电话!!"); } } class SmartPhone extends Phone { //构造方法 constructor(brand, price, color, size){ super(brand, price);// Phone.call(this, brand, price) this.color = color; this.size = size; } photo(){ console.log("拍照"); } playGame(){ console.log("玩游戏"); } call(){ console.log('我可以进行视频通话'); } } const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch'); console.log(xiaomi); xiaomi.call(); xiaomi.photo(); xiaomi.playGame();
- ES6 中直接使用 extends 语法糖(更简洁高级的实现方式)来实现继承,同时可以重写父类的方法,直接在子类中重新写一次要重写的方法即可覆盖父类方法。
- getter和setter🔥
- 当属性拥有 get/set 特性时,属性就是访问器属性。代表着在访问属性或者写入属性值时,对返回值做附加的操作。而这个操作就是 getter/setter 函数。
- 使用场景: getter 是一种语法,这种 get 将对象属性绑定到 查询该属性时将被调用的函数。适用于某个需要动态计算的成员属性值的获取。setter 则是在修改某一属性时所给出的相关提示。
// get 和 set class Phone{ get price(){ console.log("价格属性被读取了"); return 'iloveyou'; } set price(newVal){ console.log('价格属性被修改了'); } } //实例化对象 let s = new Phone(); console.log(s.price); s.price = 'free';
📚数值扩展
Number.EPSILON
是 JavaScript 表示的最小精度,一般用来处理浮点数运算。例如可以用于两个浮点数的比较。let equal = (x, y) => Math.abs(x - y) < Number.EPSILON; console.log(0.1 + 0.2 === 0.3); // false console.log(equal(0.1 + 0.2, 0.3)); // true
Number.isFinite
检测一个数值是否为有限数。console.log(Number.isFinite(100)); // false console.log(Number.isFinite(100 / 0)); // true console.log(Number.isFinite(Infinity)); // false
- ES6 给 Number 添加了 parseInt 方法,
Number.parseInt
完全等同于 parseInt,将字符串转为整数,或者进行进制转换。Number.parseFloat
则等同于 parseFloat()。 Number.isInteger()
判断一个数是否为整数。Math.trunc()
将数字的小数部分抹掉。Math.sign
判断一个数到底为正数 负数 还是零
📚对象方法扩展
Object.is
比较两个值是否严格相等,与『===』行为基本一致。Object.assign
对象的合并,将源对象的所有可枚举属性,复制到目标对象。__proto__
、setPrototypeOf
、setPrototypeOf
可以直接设置对象的原型。
📚ES6模块化
- 模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
- 模块化的好处
- 防止命名冲突
- 代码复用
- 高维护性
- ES6模块化语法 :模块功能主要由两个命令构成:
export
和import
。- export命令用于规定模块的对外接口。
- import命令用于输入其他模块提供的功能。
🐇模块导出数据语法
- 单个导出
// 单个导出 export let uname = 'Rick'; export let sayHello = function () { console.log('Hi, bro!'); }
- 合并导出
let uname = 'Rick'; let sayHello = function () { console.log('Hi, bro!'); } // 合并导出 export { uname, sayHello };
- 默认导出
// 默认导出 export default { uname: 'Rick', sayHello: function () { console.log('Hi, bro!'); } }
🐇模块导入数据语法
- 通用导入
import * as m1 from './js/m1.js'; import * as m2 from './js/m2.js'; import * as m3 from './js/m3.js';
- 解构赋值导入
import { uname, sayHello } from './js/m1.js'; // 有重复名可以设置别名 import { uname as uname2, sayHello as sayHello2 } from './js/m2.js'; console.log(uname); // 配合默认导出 import {default as m3} from "./src/js/m3.js";
- 简便方式导入,针对默认暴露
import m3 from "./src/js/m3.js";