文章目录
- 📚迭代器
- 🐇定义
- 🐇工作原理
- 🐇自定义遍历数据
- 📚生成器函数
- 🐇声明和调用
- 🐇生成器函数的参数传递
- 🐇生成器函数案例
- 📚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接口的数据// 遍历 Mapconst 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>//声明一个 setlet 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";