01-JS原生
码路教育 6/28/2001
# 一. 手写call的实现原理
<script>
// call的原理
(function() {
function mlcall(context) {
context = context ? Object(context) : window;
// this就是fn
// this() fn()
context.f = this;
let args = []; // 收集函数的参数
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
let res = context.f(...args)
delete context.f;
return res;
}
Function.prototype.mlcall = mlcall;
}())
function fn(num1, num2) {
console.log(this);
return num1 + num2
}
let obj = {
name: "码路"
}
// 1)改变fn中this的指向
// 2)call可以让函数调用
// 3)返回函数调用的结果
// let res = fn.call(obj, 6, 8)
let res = fn.mlcall(obj, 6, 8)
console.log(res)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 二. 手写apply的实现原理
<script>
// apply的原理
(function() {
function mlapply(context, args) {
context = context ? Object(context) : window;
// this 表示fn
// this() 不OK
context.f = this;
if (!args) {
return context.f();
}
let res = context.f(...args)
delete context.f;
return res;
}
Function.prototype.mlapply = mlapply;
}())
function fn(num1, num2) {
console.log(this);
return num1 + num2
}
let obj = {
name: "码路"
}
// 1)改变fn中this的指向
// 2)apply可以让函数调用
// 3)返回函数调用的结果
// let res = fn.apply(obj, [6, 8])
let res = fn.mlapply(obj, [6, 8])
console.log(res)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 三. 手写bind的实现原理
<script>
// bind实现原理
(function() {
function mlbind(context) {
let bindArgs = Array.prototype.slice.call(arguments, 1);
// this 表示fn this()不OK
let that = this;
function gn() {
let args = Array.prototype.slice.call(arguments);
return that.apply(context, bindArgs.concat(args))
}
return gn;
}
Function.prototype.mlbind = mlbind;
})()
function fn(num1, num2) {
console.log(this);
return num1 + num2;
}
let obj = {
name: "码路"
}
// 1)改变fn中this的指向
// 2)返回一个绑定this后的函数
// let res = fn.bind(obj, 1)
let res = fn.mlbind(obj, 1)
console.log(res(2));
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 四. 手写new的实现原理
< script >
function Dog(name) {
this.name = name;
// return {a:1}
return function() {
console.log("xx");
}
}
Dog.prototype.bark = function() {
console.log('wangwang');
}
Dog.prototype.sayName = function() {
console.log('my name is ' + this.name);
}
// (1)在构造器内部创建一个新的对象
// (2)这个对象内部的__proto__属性会被赋值为该构造函数的prototype属性;
// (3)让构造器中的this指向这个对象
// (4)执行构造器中的代码
// (5)如果构造器没有返回对象或函数,则返回上面的创建出来的对象
// let malu = new Dog('码路');
// console.log(malu);
// malu.sayName();
// malu.bark();
function _new(Ctor, ...args) {
//=>完成你的代码
if (!Ctor.hasOwnProperty("prototype")) {
throw new TypeError("Ctor is not a constructor")
}
let obj = Object.create(Ctor.prototype)
let result = Ctor.apply(obj, args)
if (result !== null && (typeof result == "object" || typeof result == "function")) {
return result;
}
return obj;
}
let malu = _new(Dog, '码路');
console.log(malu);
// malu.bark(); //=>"wangwang"
// malu.sayName(); //=>"my name is 码路"
// console.log(malu instanceof Dog); //=>true
<
/script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 五. 手写实现深copy
<script>
// 实现深copy
function deepClone(target, weakMap = new WeakMap()) {
if (target == null) return target;
if (target instanceof Date) return new Date(target);
if (target instanceof RegExp) return new RegExp(target)
// .....
if (typeof target !== "object") return target;
let cloneTarget = new target.constructor;
if (weakMap.get(target)) {
return weakMap.get(target)
}
weakMap.set(target, cloneTarget)
for (let key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone(target[key], weakMap)
}
}
return cloneTarget;
}
let obj = {
name: "码路",
address: {
city: "北京"
}
};
obj.xxx = obj; // 循环引用
let newObj = deepClone(obj);
console.log(newObj); < /script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 六. 实现(a == 1 && a == 2 && a == 3)为true
<script>
// a等于什么值,会使条件成⽴「两种⽅案」
// var a = "?";
// valueOf方法
// 解法一
// let a = {
// i:0,
// valueOf(){
// return ++this.i
// }
// }
// 解法二
// let a = {
// i:0,
// toString(){
// return ++this.i
// }
// }
// 解法三
// let a = [1,2,3];
// a.toString = a.shift;
// 解法四
let i = 0;
Object.defineProperty(window, "a", {
get() {
// console.log("get...");
return ++i;
}
})
if (a == 1 && a == 2 && a == 3) {
console.log('码路教育');
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 七. 如何给数组降维
<script>
// 利用Array.some方法判断数组中是否还存在数组,es6展开运算符连接数组
let arr = [1, 2, [3, 4, [5]]]
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
console.log(arr);
</script>
<script>
// 使用数组的concat方法
let arr = [1, 2, [3, 4]]
let result = []
// result = Array.prototype.concat.apply([], arr)
result = [].concat(...arr)
console.log(result);
</script>
<script>
// es6中的flat函数也可以实现数组的扁平化
let arr = [1, 2, ['a', 'b', ['中', '⽂', [1, 2, 3, [11, 21, 31]]]], 3];
let result = arr.flat(Infinity)
console.log(result);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 八. 一个关于闭包的经典面试题
<script>
// 下面代码是否可以,每隔1000MS依次输出 0 1 2 3 4 5 ?
// 如果不可以,说明为啥?以及如何解决?
// for循环是同步代码 定时器是异步代码
// 同步代码执行完毕后,i的值已经变了6
// for (var i = 0; i < 6; i++) {
// setTimeout(function () {
// console.log(i);
// }, (i + 1) * 1000);
// }
// 利用闭包解决
// for (var i = 0; i < 6; i++) {
// (function (i) {
// setTimeout(function () {
// console.log(i);
// }, (i + 1) * 1000);
// })(i)
// }
// 利用块级作用域
// let + {} 会形成块级作用域
// for (let i = 0; i < 6; i++) {
// setTimeout(function () {
// console.log(i);
// }, (i + 1) * 1000);
// }
// 利用闭包解决
for (let i = 0; i < 6; i++) {
setTimeout((function(i) {
return function() {
console.log(i);
}
})(i), i * 1000)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 九. 检测一个对象是否是纯对象
<script>
// 检测一个对象是否是纯对象
const isPlainObject = function isPlainObject(obj) {
let prototype;
return Object.prototype.toString.call(obj) === '[object Object]' &&
(prototype = Object.getPrototypeOf(obj), prototype === null ||
prototype == Object.getPrototypeOf({})
)
};
// {} new Object() Object.create(null)
console.log(isPlainObject({}));
console.log(isPlainObject(new Object()));
console.log(isPlainObject(Object.create(null)));
console.log("-------------");
function Person() {}
let p = new Person()
console.log(isPlainObject(new Array()));
console.log(isPlainObject(p));
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 十. 手写JSONP实现原理
前端代码
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<button id="btn">发送ajax请求</button>
<script>
let btn = document.getElementById("btn");
function jsonp(options) {
let callBackName = "wangcai";
window[callBackName] = function(data) {
if (data != null) {
options.success(data)
} else {
options.fail()
}
}
let url = options.url + "?callBack=" + callBackName
let scriptEle = document.createElement("script");
scriptEle.src = url;
document.body.append(scriptEle)
}
btn.onclick = function() {
jsonp({
url: "http://localhost:3000/",
success: function(data) {
console.log("data:", data);
},
fail: function(err) {
console.log("数据请求失败了");
}
})
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
后端代码
const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();
app.use(cors());
app.use(logger());
app.use(koaBody());
router.get("/", (ctx) => {
let cb = ctx.query.callBack;
// console.log(cb);
// 后端返回函数调用字符串
ctx.body = `${cb}(${JSON.stringify({ a: 1, b: 2 })})`
})
app.use(router.routes())
router.allowedMethods();
app.listen(3000, () => {
console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 十一. Vue2数据响应式原理
<script>
// vue2.x的响应式原理
function updateView() {
console.log("视图更新了~");
}
function definedReactive(target, key, value) {
// console.log(target,key,value);
observer(value); // 深度监听
Object.defineProperty(target, key, {
get() {
// console.log("get...");
return value
},
set(newValue) {
observer(newValue); // 深度监听
value = newValue
// 数据变了,我监听到了,我要去更新视图
updateView()
}
})
}
function observer(target) {
if (typeof target !== "object" || target === null) {
return target
}
for (let key in target) {
definedReactive(target, key, target[key])
}
}
// 准备数据
// 目的:name,age,info,address
let data = {
name: "码路",
age: 18,
info: {
address: "bj",
}
};
// 监听数据,数据劫持
observer(data)
// 当数据变了,要更新视图
// console.log(data.name);
// data.name = "malu";
// console.log(data.name);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 十二. Vue2数组响应式原理
<script>
// vue2.x的响应式原理
function updateView() {
console.log("视图更新了~");
}
// 把Array的原型对象,赋值给oldArrayProperty
let oldArrayProperty = Array.prototype;
let arrProto = Object.create(oldArrayProperty);
["push", "pop", "shift", "unshift", "splice"].forEach(methodName => {
// console.log(methodName);
// 调用这7个方法时,调用的并不是原生的push是我们自己重写后的push
arrProto[methodName] = function() {
updateView(); // 更新视图
oldArrayProperty[methodName].call(this, ...arguments)
}
})
function definedReactive(target, key, value) {
// console.log(target,key,value);
observer(value); // 深度监听
Object.defineProperty(target, key, {
get() {
// console.log("get...");
return value
},
set(newValue) {
observer(newValue); // 深度监听
value = newValue
// 数据变了,我监听到了,我要去更新视图
updateView()
}
})
}
function observer(target) {
if (typeof target !== "object" || target === null) {
return target
}
if (Array.isArray(target)) {
// console.log(target+"是数组");
// 如果是数组,改变原型对象
target.__proto__ = arrProto;
}
for (let key in target) {
definedReactive(target, key, target[key])
}
}
// 准备数据
// 目的:name,age,info,address
let data = {
name: "码路",
age: 18,
info: {
address: "bj",
},
arr: ["ml", "wc", "xq"]
};
// data.arr.push("z3") 当调用push时,模板也需要重新渲染
// 在vue2.x中重写了数组的7个方法,在7个方法中更新了视图
// 监听数据,数据劫持
observer(data)
// 当数据变了,要更新视图
// console.log(data.name);
// data.name = "malu";
// console.log(data.name);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 十三. 防抖实现
<!--
说说你对防抖、 节流的理解, 以及它们的区别和应用场景?
防抖: 将多次执行函数变成最后⼀ 次执行 等待固定时间还没有事件触发时执行的函数
应用场景:
按钮的点击
屏幕滚动时的复杂计算
输⼊ 框输⼊ 时进行搜索
用户缩放浏览器的resize事件
简单的防抖函数实现:
-->
<script>
function myDebounce(execFn, delay) {
let timer = 0
function _debounce(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
execFn.apply(this, args)
timer = null
}, delay)
}
return _debounce
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 十四. 节流实现
<!--
节流: 按照固定的时间频率(间隔)来执⾏对应的函数
应用场景:
监听页面的滚动事件 通过节流来降低事件调用的频率
⿏标移动
用户频繁点击按钮的操作
简单实现:
-->
<script>
function myThrottle(execFn, interval) {
let initTime = 0
function throttle(...args) {
let nowTime = Date.now()
const waitTime = interval - (nowTime - initTime)
if (waitTime <= 0) {
execFn.apply(this, args)
initTime = nowTime
}
}
return throttle
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 十五. 数组去重
<script>
// 利用ES6 Set去重(ES6中最常用)
function unique(arr) {
return Array.from(new Set(arr))
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<script>
// 利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) { //第⼀个等同于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
// [1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
// 利用indexOf去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
return array;
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {… }] //NaN、{}没有去重
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
// 利用sort去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined] // NaN、{}没有去重
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
// 利用includes
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (!array.includes(arr[i])) { //includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
// {} 没有去重
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
// 利用filter
function unique(arr) {
return arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第⼀个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
</script>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<script>
// 利用递归去重
function unique(arr) {
return arr.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []);
}
var arr = [1, 1, 'true', 'true', true, true, 15, 15, false, false, undefined, undefined, null, null, NaN, NaN, 'NaN', 0, 0, 'a', 'a', {}, {}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 十六. JS继承实现方案
- 参考:http://47.94.210.129/malulesson/basic/jsplus/06.html
# 十七. 实现柯里化函数
<script>
function mlcurrying(fn, ...args1) {
let length = fn.length;
let allArgs = [...args1];
let res = (...args2) => {
allArgs = [...allArgs, ...args2]
if (allArgs.length == length) {
return fn(...allArgs)
} else {
return res;
}
}
return res;
}
// 测试:
const add = (a, b, c) => a + b + c;
const a = mlcurrying(add, 1);
console.log(a(2, 3)) // 6
const b = mlcurrying(add, 1, 2, 3);
console.log(b()) // 6
const c = mlcurrying(add);
console.log(c(1, 2, 3)) // 6
const d = mlcurrying(add, 1)
console.log(d(2)(3)); // 6
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 十八. 使用setTimeout实现setInterval
<script>
// 使用setTimeout实现setInterval
function mlSetTimout(fn, delay) {
let timer = null;
let interval = () => {
fn();
timer = setTimeout(interval, delay)
}
setTimeout(interval, delay)
return {
cancel() {
clearTimeout(timer)
}
}
}
// mlSetTimout(() => console.log(888), 1000);
let {
cancel
} = mlSetTimout(() => console.log(888), 1000);
setTimeout(() => {
cancel();
}, 5000);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 十九. 简单实现hash路由
<html>
<style>
html,
body {
margin: 0;
height: 100%;
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
}
.box {
width: 100%;
height: 100%;
background-color: red;
}
</style>
<body>
<ul>
<li>
<a href="#red">红色</a>
</li>
<li>
<a href="#green">绿色</a>
</li>
<li>
<a href="#purple">紫色</a>
</li>
</ul>
<div class="box"></div>
<!-- <script>
let box = document.getElementsByClassName("box")[0];
window.onhashchange = function () {
let color = location.hash.slice(1);
box.style.background = color
}
</script> -->
<script>
// 封装成一个类
let box = document.getElementsByClassName("box")[0];
class HashRouter {
constructor(hashStr, cb) {
this.hashStr = hashStr;
this.cb = cb;
this.watchHash()
window.addEventListener("hashchange", this.watchHash.bind(this))
}
watchHash() {
let hash = location.hash.slice(1)
this.hashStr = hash;
this.cb(this.hashStr)
}
}
new HashRouter("red", (color) => {
box.style.background = color;
});
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 二十. 手写Promise.all的实现
<script>
// 类方法(静态方法) all
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p2 resolve")
reject("p2 reject error")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
// const p4 = 110;
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
let result = [];
let index = 0;
let len = promises.length;
if (len === 0) {
resolve(result)
return;
}
for (let i = 0; i < len; i++) {
// promises[i]
Promise.resolve(promises[i]).then(data => {
result[i] = data;
index++;
if (index === len) {
resolve(result)
}
}).catch(err => {
reject(err)
})
}
})
}
// 类方法(静态方法) all
// all的作用:所有promise都成功后,得到所有成功后的promise结果
// 如果有一个先失败了,直接得到最先失败promise的结果
Promise.all([p1, p2, p3]).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 二十一. 手写Promise.allSettled的实现
<script>
// 类方法(静态方法) allSettled
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1 resolve")
// reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2 resolve")
// reject("p2 reject error")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
function isPromise(val) {
return typeof val.then === "function"
}
Promise.allSettled = function(promises) {
return new Promise((resolve, reject) => {
let arr = [];
let times = 0;
let setData = (index, data) => {
arr[index] = data;
if (++times === promises.length) {
resolve(arr)
}
}
for (let i = 0; i < promises.length; i++) {
let current = promises[i];
if (isPromise(current)) {
current.then(data => {
setData(i, {
status: 'fulfilled',
value: data
})
}, err => {
setData(i, {
status: 'rejected',
value: err
})
})
} else {
setData(i, {
status: 'rejected',
value: current
})
}
}
})
}
// allSettled 获取所有的promise的结果,不管成功还是失败
Promise.allSettled([p1, p2, p3]).then(res => {
console.log("all settled:", res)
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 二十二. 手写Promise.race的实现
<script>
// 创建三个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p1 resolve")
reject("p1 reject error")
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("p2 resolve")
reject("p2 reject error")
}, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p3 resolve")
}, 5000)
})
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
let len = promises.length;
if (len === 0) return;
for (let i = 0; i < len; i++) {
Promise.resolve(promises[i]).then(data => {
resolve(data)
return;
}).catch(err => {
reject(err);
return;
})
}
})
}
// 类方法: race方法 race是比赛的意思
// 特点: 会等到第一个Promise有结果(无论这个结果是fulfilled还是rejected)
Promise.race([p1, p2, p3]).then(res => {
console.log("race promise:", res)
}).catch(err => {
console.log("race promise err:", err)
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 二十三. 实现 (5).add(3).minus(2)
<script>
// 实现 (5).add(3).minus(2) 功能
Number.prototype.add = function(n) {
return this.valueOf() + n;
}
Number.prototype.minus = function(n) {
return this.valueOf() - n;
}
// console.log((5).add(3));
console.log((5).add(3).minus(2));
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 二十四. alert(add(1)(2)(3)(4)(5))
<script>
// 实现 alert(add(1)(2)(3)(4)(5))
function add(x) {
let sum = x; // sum是存储和
let tmp = function(y) {
sum = sum + y;
return tmp;
}
tmp.toString = function() {
return sum;
}
return tmp;
}
// 当alert时,会调用toString方法
alert(add(1)(2)(3)(4)(5))
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 二十五. 工具函数之封装判断数据类型的函数
<script>
// 工具函数之封装判断数据类型的函数
// Object.prototype.toString()
function getType(data) {
if (data === null) return String(data)
return typeof data === "object" ? Object.prototype.toString.call(data).replace('[object ', '').replace(']', '').toLowerCase() : typeof data
}
// 调用
console.log(getType(null)); // -> null
console.log(getType(undefined)); // -> undefined
console.log(getType({})); // -> object
console.log(getType([])); // -> array
console.log(getType(123)); // -> number
console.log(getType(true)); // -> boolean
console.log(getType('码路')); // -> string
console.log(getType(/123/)); // -> regexp
console.log(getType(new Date())); // -> date
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 二十六. 实现深度比较isEqual
<script>
// 是不是对象
function isObject(obj) {
return typeof obj === "object" && obj !== null;
}
// 深度比较
function isEqual(obj1, obj2) {
if (!isObject(obj1) || !isObject(obj2)) {
// 说明其中有一个数据是基本数据类型
return obj1 === obj2
}
// 两个都是对象或数组,比较key的个数是否相同
let obj1Keys = Object.keys(obj1)
let obj2Keys = Object.keys(obj2)
if (obj1Keys.length !== obj2Keys.length) {
return false;
}
// 两个对象或数组中的key的个数是一样的
// 以其中一个为基准,遍历,递归比较
for (let key in obj1) {
// console.log(obj1[key]);
let res = isEqual(obj1[key], obj2[key])
if (!res) {
return false;
}
}
// 全相等
return true;
}
let obj1 = {
a: 1,
b: 2,
c: {
d: "d",
e: 'e'
}
}
let obj2 = {
a: 1,
b: 2,
c: {
d: "d",
e: 'e'
}
}
console.log(isEqual(obj1, obj2)); // true
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 二十七. 数组并集,交集,差集
<script>
// 并集
// [1,2,3] 并 [4,5,6] ==> [1,2,3,4,5,6]
// [1,2,3,3] 并 [4,5,6,6] ==> [1,2,3,4,5,6]
// [1,2,3,3] 并 [3,6,6] ==> [1,2,3,6]
let arr1 = [1, 2, 3, 3];
let arr2 = [4, 5, 6, 3, 2, 4, 9];
function union(arr1, arr2) {
let res = new Set([...arr1, ...arr2])
return [...res]
}
let newArr = union(arr1, arr2);
console.log(newArr)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
// 交集
// [1,2,3] 交 [3,4,5,6] ==> [3]
// [1,2,3] 交 [7,8,9] ==> []
// [1,2,3] 交 [1,2,3] ==> [1,2,3]
let arr1 = [1, 2, 3, 3];
let arr2 = [3, 4, 5, 5];
function intersection(arr1, arr2) {
let s1 = new Set(arr1)
let s2 = new Set(arr2)
let newArr = [...s1].filter(item => {
return s2.has(item)
})
return newArr
}
let newArr = intersection(arr1, arr2);
console.log(newArr)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
// 差集
// [1,2,3] 差 [3,4,5] ==> [1,2]
// [3,4,5] 差 [1,2,3] ==> [4,5]
let arr1 = [1, 2, 3];
let arr2 = [3, 4, 5];
function except(arr1, arr2) {
let s1 = new Set(arr1)
let s2 = new Set(arr2)
let newArr = [...s1].filter(item => {
return !s2.has(item)
})
return newArr;
}
console.log(except(arr1, arr2)) // [1,2]
console.log(except(arr2, arr1)) // [4,5]
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 二十八. 实现map方法
<script>
// 实现数组的map方法
Array.prototype.mlmap = function(fn) {
let newArr = [];
// this arr打点调用mlmap方法,mlmap方法中this表示arr
for (let i = 0; i < this.length; i++) {
let res = fn(this[i], i, this)
newArr.push(res)
}
return newArr;
};
var arr = [1, 3, 6];
// map可以对数组中每一个元素进行加工
// map返回加工后的新数组
var result = arr.mlmap(function(element, index, array) {
console.log("index", index);
console.log("array", array);
return element * element;
});
console.log("result: ===", result);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 二十九. 实现数组find方法
<script>
// 实现数组find方法
Array.prototype.mlfind = function(fn) {
// this是arr
for (let i = 0; i < this.length; i++) {
let res = fn(this[i])
if (res) {
// 表示元素满足条件
return this[i];
}
}
};
var arr = [1, 3, 6, 90, 23];
// find:查找满足条件的第1个元素
// item表示数组中每一个元素
var result = arr.mlfind(function(item) {
// 指定查找条件
return item > 6;
});
console.log(result);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 三十. 实现filter函数
<script>
//模拟实现filter函数
Array.prototype.mlfilter = function(fn) {
let newArr = [];
// this表示array
for (let i = 0; i < this.length; i++) {
let res = fn(this[i])
if (res) {
newArr.push(this[i])
}
}
return newArr;
};
var array = [65, 56, 89, 53];
// filter是用来过滤数组中符合某个条件的元素
var arr = array.mlfilter(function(item) {
return item >= 60;
});
console.log("arr=>", arr);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 三十一. 实现some方法
<script>
//实现some方法
Array.prototype.mlsome = function(fn) {
// this 表示array
for (let i = 0; i < this.length; i++) {
let res = fn(this[i])
if (res) {
return res;
}
}
return false
};
let array = [1, 3, 5, 7, 90];
// 只要数组中一个元素满足条件,结果就true
let result = array.mlsome(function(item) {
return item > 10;
});
console.log("result=>", result);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 三十二. 实现every方法
<script>
//手动模拟实现every方法
Array.prototype.mlevery = function(fn) {
let flag = true;
// this
for (let i = 0; i < this.length; i++) {
let res = fn(this[i])
if (!res) {
// 有一个元素不满足条件
return false;
}
}
return flag
};
let array = [11, 31, 5, 71, 90];
// 如果数组中每一个元素都满足条件,结果就是true
// 只要有一个不满足结果就是false
let result = array.mlevery(function(item) {
return item > 10;
});
console.log("result=", result);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 三十三. 实现findIndex方法
<script>
// findIndex的实现
Array.prototype.mlfindIndex = function(fn) {
// this 表示arr
for (let i = 0; i < this.length; i++) {
if (fn(this[i], i)) {
return i
}
}
}
let arr = [1, 3, 4, 5, 7, 8];
// 找到满足条件的第1个元素的索引
let res = arr.mlfindIndex((item, index) => {
return item % 2 === 1
})
console.log(res)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 三十四. 实现reduce方法
<script>
// 实现reduce方法
Array.prototype.mlreduce = function(fn, initVal) {
// 给prev传递了初始化参数,也就是说有初始化参数
let hasInitVal = initVal !== undefined
let value = hasInitVal ? initVal : this[0]
for (let i = hasInitVal ? 0 : 1, len = this.length; i < len; i++) {
value = fn(value, this[i], i, this)
}
return value;
};
var arr = [1, 2, 3];
// reduce是个累加器
// 第1次:prev:1 next:2
// 第2次:prev:3 next:3
// 第3次:prev:6 next:无
// prev表示之前累加和 next表示下一项
// 在调用reduce时可以给prev传递初始化参数
var sum = arr.mlreduce(function(prev, next, index, arr) {
// console.log("prev", prev);
// console.log("next", next);
return prev + next;
}, 10);
console.log(sum);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 三十五. 实现concat方法
<script>
// 实现concat方法
Array.prototype.mlconcat = function myconcat(...values) {
let newArr = [];
newArr.push(...this)
if (values.length === 0) {
return newArr
}
values.forEach(value => {
if (Array.isArray(value)) {
newArr.push(...value)
} else {
newArr.push(value)
}
})
return newArr;
}
let arr1 = [1, 2];
let arr2 = [3, 4];
let arr3 = [5, 6];
let arr4 = [7, 8];
// concat拼接多个数组形成一个数组
// 拼接也可以是一个普通值 返回一个新的数组
console.log(arr1.mlconcat(arr2, arr3, arr4, "hello"))
console.log(arr1.mlconcat("malu"))
console.log(arr1.mlconcat())
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 三十六. 实现slice方法
<script>
// 实现slice方法
Array.prototype.mlslice = function(start, end) {
let newArr = [];
// this表示arr1
// 如果要截取的数组是一个空数组,什么也不做,直接返回空数组
if (this.length === 0) {
return newArr;
}
// 处理start特殊情况
start = start || 0
if (start < 0) {
start = this.length + start
} else if (start >= this.length) {
return newArr;
}
// 处理end的特殊的情况
end = end || this.length;
if (end > this.length) {
end = this.length;
} else if (end <= start) {
end = this.length + end;
}
for (let i = start; i < end; i++) {
newArr.push(this[i])
}
return newArr;
}
// slice() 方法可从已有的数组中返回选定的元素。
// 返回一个新的数组,包含从 start(包括该元素) 到 end (不包括该元素)的 arrayObject 中的元素。
// start:规定从何处开始选取。如果该参数为负数,
// 则表示从原数组中的倒数第几个元素开始提取,
// slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)
// end:规定从何处结束选取。该参数是数组片断结束处的数组下标。
// 如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。
// 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。
// slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)
let arr1 = [1, 3, 4, 5, 7, 9];
let res1 = arr1.mlslice(2, 4); // 2 4 代表都是索引
console.log(res1); // [4, 5]
let res2 = arr1.mlslice(-2, -1);
console.log(res2); // [7]
let res3 = arr1.mlslice();
console.log(res3) // [1, 3, 4, 5, 7, 9]
let res4 = arr1.mlslice(2);
console.log(res4) // [1, 3, 4, 5, 7, 9]
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 三十七. 实现发布订阅
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button class="btn">点我</button>
<script>
// 实现发布订阅 事件总线
// 订阅 发布
class MyEventBus {
constructor() {
// {"malu":[f1,f2]}
this.eventMap = {}
}
on(eventName, eventFn) {
let eventFns = this.eventMap[eventName]
if (!eventFns) {
eventFns = [];
this.eventMap[eventName] = eventFns
}
eventFns.push(eventFn)
}
off(eventName, eventFn) {
let eventFns = this.eventMap[eventName];
if (!eventFns) return;
// {eat:[f1,f2,f3...]}
for (let i = 0; i < eventFns.length; i++) {
let fn = eventFns[i];
if (fn === eventFn) {
eventFns.splice(i, 1)
break;
}
}
// 如果eventFns已经清空了
if (eventFns.length === 0) {
delete this.eventMap[eventName]
}
}
emit(eventName, ...args) {
let eventFns = this.eventMap[eventName];
if (!eventFns) return;
eventFns.forEach(fn => {
fn(...args)
})
}
}
// 使用过程
const eventBus = new MyEventBus()
// 实现订阅
eventBus.on("malu", (name, age, height) => {
console.log("malu事件监听器01:", name, age, height);
})
let eat = (name, age, height) => {
console.log("eat事件监听器02", name, age, height);
};
eventBus.on("eat", eat)
setTimeout(() => {
eventBus.off("eat", eat)
}, 3000)
const btn = document.querySelector(".btn")
btn.onclick = function() {
// 发布
// eventBus.emit("malu", "wc", 18, 1.88)
eventBus.emit("eat", "wc", 18, 1.88)
}
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 三十八. 实现Promise的resolve
<script>
// 实现 resolve 静态方法有三个要点:
// 传参为一个 Promise, 则直接返回它。
// 传参为一个 thenable 对象,返回的 Promise 会跟随这个对象,
// 采用它的最终状态作为自己的状态。
// 其他情况,直接返回以该值为成功状态的promise对象。
// 实现Promise中resolve静态方法
Promise.resolve = (param) => {
if (param instanceof Promise) return param
return new Promise((resolve, reject) => {
if (param && param.then && typeof param.then === "function") {
// console.log("传递的是一个thenable");
param.then(resolve, reject)
} else {
resolve(param)
}
})
}
const p1 = new Promise((resolve, reject) => {
resolve("p1 resolve")
// reject("p1 reject error")
})
// Promise.resolve("码路").then(res => {
// Promise.resolve(p1).then(res => {
Promise.resolve({
then(resolve, reject) {
resolve("p1 resolve")
}
}).then(res => {
console.log("then结果:", res)
})
// 相当于
// new Promise((resolve) => {
// resolve("hello")
// })
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 三十九. 迭代器
<script>
// 什么是迭代器
const names = ["码路", "漫漫", "前端"];
// 给数组names创建一个迭代器(迭代器: names的迭代器)
let index = 0
// 迭代器就是一个对象,要求这个对象必须有一个next方法
// Iterator 是迭代器 就可以把一个容器中的元素迭代出来
const namesIterator = {
next() {
if (index < names.length) {
return {
done: false,
value: names[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
};
// 调用next返回一个对象,done表示是否迭代完毕,value表示迭代出来的数据
console.log(namesIterator.next()); // { done:false,value:"码路" }
console.log(namesIterator.next()); // { done:false,value:"漫漫" }
console.log(namesIterator.next()); // { done:false,value:"前端" }
console.log(namesIterator.next()); // { done:false,value:undefined }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script>
const nums = [100, 200, 300, 400, 500]
let index = 0;
let numsIterator = {
next() {
if (index < nums.length) {
return {
done: false,
value: nums[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
console.log(numsIterator.next()); // { done: false, value: 100 }
console.log(numsIterator.next()); // { done: false, value: 200 }
console.log(numsIterator.next()); // { done: false, value: 300 }
console.log(numsIterator.next()); // { done: false, value: 400 }
console.log(numsIterator.next()); // { done: false, value: 500 }
console.log(numsIterator.next()); // { done: false, value: undefined }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script>
// 封装一个函数,返回一个数组迭代器(Iterator)
const nums = [100, 200, 300, 400, 500]
const names = ["码路", "漫漫", "前端"];
function createArrayIterator(arr) {
let index = 0;
return {
next() {
if (index < arr.length) {
return {
done: false,
value: arr[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
}
let namesIterator = createArrayIterator(names);
console.log(namesIterator.next());
console.log(namesIterator.next());
console.log(namesIterator.next());
let numsIterator = createArrayIterator(nums);
console.log(numsIterator.next());
console.log(numsIterator.next());
console.log(numsIterator.next());
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 四十. 可迭代对象
<meta charset="utf-8" />
<script>
// 可迭代对象
// 满足条件1:必须实现一个特定的函数: [Symbol.iterator]
// 满足条件2:这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
// infos就可以叫做可迭代对象
let infos = {
friends: ["码路", "漫漫", "前端"],
[Symbol.iterator]() {
let index = 0;
let infosIterator = {
next() {
if (index < infos.friends.length) {
return {
done: false,
value: infos.friends[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
return infosIterator;
}
};
// 返回了迭代器
// let iterator = infos[Symbol.iterator]();
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// 只要是一个可迭代对象,都可以使用for of进行遍历
// infos is not iterable
for (let item of infos) {
console.log(item);
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<script>
// 可迭代对象
let infos2 = {
name: "码路",
age: 18,
height: 1.88,
[Symbol.iterator]() {
let entries = Object.entries(this);
// console.log("entries:", entries);
// iterator迭代器
// iterable可迭代的
let index = 0;
let infos2Iterator = {
next() {
if (index < entries.length) {
return {
done: false,
value: entries[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
return infos2Iterator;
}
};
// 可迭代对象必然具备下面的特点
// const iterator = infos2[Symbol.iterator]()
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// 只要是可迭代对象,都可以使用for of
for (let item of infos2) {
console.log(item);
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<script>
// JS中哪些容器天生就是可迭代对象
// 1)数组
// const names = ["aaa", "bbb", "ccc"]
// for (const name of names) {
// console.log(name)
// }
// let iterator = names[Symbol.iterator](); // 得到迭代器
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log("---------------");
// 2)Set
// new Set时 ()中只要写可迭代对象都可以
// ["aaa", "bbb", "ccc"] 就是一个迭代对象
// const set = new Set(["aaa", "bbb", "ccc"])
// for (const item of set) {
// console.log(item)
// }
// const setIterator = set[Symbol.iterator]()
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log("---------------");
// 3)arguments
// function foo() {
// for (const arg of arguments) {
// console.log(arg)
// }
// }
// foo(111, 222, 333, 444)
// console.log("---------------");
// 4)字符串
// let str = "hello";
// for (let item of str) {
// console.log(item);
// }
// console.log("---------------");
// 对象不是可迭代对象
// let obj = {
// name: "wc",
// age: 18,
// sex: "man"
// }
// // TypeError: obj is not iterable
// // iterable 可迭代的
// for (let item of obj) {
// console.log(item);
// }
let obj = {
a: 1,
b: 2,
c: 3
}
let res = {
...obj
}
console.log(res);
function fn(x, y, z) {
console.log(x, y, z);
}
fn(obj.a, obj.b, obj.c)
// requires ...iterable[Symbol.iterator] to be a function
fn(...obj)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 四十一. 迭代对象的应用场景
<meta charset="utf-8">
<script>
// 之前说过: 迭代器 可迭代对象
// 可迭代对象的应用场景: 把一个非可迭代对象 转化成 可迭代对象
const info = {
name: "码路",
age: 18,
height: 1.88,
[Symbol.iterator]() {
let values = Object.values(this)
// console.log(values);
let index = 0;
let iterator = {
next() {
if (index < values.length) {
return {
done: false,
value: values[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
return iterator;
}
};
let iterator = info[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<meta charset="utf-8">
<script>
// 可迭代对象的应用场景: 一些类的构造方法中, 也是传入的可迭代对象
// 语法:new Set([iterable])
const set = new Set(["aaa", "bbb", "ccc"])
console.log(set);
const set2 = new Set("hello")
console.log(set2);
const set3 = new Set(set2)
console.log(set3);
</script>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<meta charset="utf-8">
<script>
// 可迭代对象的应用场景: 一些常用的方法
// const p1 = Promise.resolve("aaaa")
// const p2 = Promise.resolve("bbbb")
// const p3 = Promise.resolve("cccc")
// let set = new Set();
// set.add(p1)
// set.add(p2)
// set.add(p3)
// // all([iterable])
// Promise.all(set).then(res => {
// console.log("res:", res);
// })
function bar() {
// arguement不仅是一个伪数组,也是一个可迭代对象
console.log(arguments);
for (let item of arguments) {
console.log(item);
}
}
bar(111, 222, 333);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<meta charset="utf-8">
<script>
// 可迭代对象的应用场景: 自定义类的迭代
class Person {
constructor(name, age, height, friends) {
this.name = name
this.age = age
this.height = height
this.friends = friends
}
// 实例方法
running() {}
[Symbol.iterator]() {
let index = 0;
let iterator = {
next: () => {
if (index < this.friends.length) {
return {
done: false,
value: this.friends[index++]
}
} else {
return {
done: true,
value: undefined
}
}
}
}
return iterator;
}
}
// p1和p2不是可迭代对象
const p1 = new Person("码路", 18, 1.88, ["aaa", "bbb", "ccc"])
const p2 = new Person("漫漫", 30, 1.98, ["111", "222", "333"])
for (const item of p2) {
console.log(item)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<meta charset="utf-8">
<script>
// 可迭代对象的应用场景: 自定义类的迭代
class Person {
constructor(name, age, height, friends) {
this.name = name
this.age = age
this.height = height
this.friends = friends
}
// 实例方法
running() {}
*[Symbol.iterator]() {
yield* this.friends;
// let index = 0;
// let iterator = {
// next: () => {
// if (index < this.friends.length) {
// return { done: false, value: this.friends[index++] }
// } else {
// return { done: true, value: undefined }
// }
// }
// }
// return iterator;
}
}
// p1和p2不是可迭代对象
const p1 = new Person("码路", 18, 1.88, ["aaa", "bbb", "ccc"])
const p2 = new Person("漫漫", 30, 1.98, ["111", "222", "333"])
for (const item of p2) {
console.log(item)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 四十二. 生成器函数
<meta charset="utf-8">
<script>
// 迭代器和可迭代对象学习
// 生成器函数:
// 1.function后面会跟上符号: *
// 2.代码的执行可以被yield控制
// 3.生成器函数默认在执行时, 返回一个生成器对象
// * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
// * 当遇到yield时, 就会中断执行
// 生成器函数
function* fn() {
console.log("aaa");
console.log("bbb");
yield
console.log("ccc");
console.log("ddd");
yield
console.log("eee");
console.log("fff");
}
// 调用生成器函数,得到生成器对象
// generator 是生成器的意思
let generator = fn();
// 生成器也有一个next方法
generator.next()
generator.next()
generator.next()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<meta charset="utf-8">
<script>
// 生成器函数
// yield叫产出 产出数据
function* fn() {
console.log("aaa");
console.log("bbb");
yield "1"
console.log("ccc");
console.log("ddd");
yield "2"
console.log("eee");
console.log("fff");
}
let generator = fn();
// 第1次调用next就执行第1个yield之前的代码
// 第2次调用next就执行第2个yield之前的代码
// ...
console.log(generator.next()); // {value: '1', done: false}
console.log(generator.next()); // {value: '2', done: false}
console.log(generator.next()); // {value: undefined, done: false}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<meta charset="utf-8">
<script>
// 生成器函数
// yield叫产出 产出数据
function* fn() {
console.log("aaa");
console.log("bbb");
let num1 = yield "1"
console.log("num1:", num1);
console.log("ccc");
console.log("ddd");
let num2 = yield "2"
console.log("num2:", num2);
console.log("eee");
console.log("fff");
}
let generator = fn();
// 第1次调用next就执行第1个yield之前的代码
// 第2次调用next就执行第2个yield之前的代码
// ...
// 调用next时,可以给生成器函数传递参数 参数传递到yield前面
console.log(generator.next('666')); // {value: '1', done: false}
console.log(generator.next('888')); // {value: '2', done: false}
console.log(generator.next('333')); // {value: undefined, done: false}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<meta charset="utf-8">
<script>
function* fn() {
let num1 = yield "1"
console.log("num1:", num1);
let num2 = yield "2"
console.log("num2:", num2);
}
let generator = fn();
// 第1次调用next方法,传递的参数,生成器函数是不能接收的
// 第2次调用next方法,传递的参数,传递给了第1个yeild前面的变量
// 第3次调用next方法,传递的参数,传递给了第2个yeild前面的变量
console.log(generator.next('666')); // {value: '1', done: false}
console.log(generator.next('888')); // {value: '2', done: false}
console.log(generator.next('333')); // {value: undefined, done: false}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<meta charset="utf-8">
<script>
function* foo(name1) {
console.log("内部代码:111", name1);
console.log("内部代码:222", name1);
let name2 = yield "aaa"
console.log("内部代码:333", name2);
console.log("内部代码:444", name2);
let name3 = yield "bbb"
console.log("内部代码:555", name3);
console.log("内部代码:666", name3);
yield "ccc"
}
let generator = foo("malu")
console.log(generator.next('666'));
console.log(generator.next('888'));
console.log(generator.next('333'));
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<meta charset="utf-8">
<script>
// 使用生成器 替代 之前讲的 迭代器
let names = ["码路", "漫漫", "前端"];
// 生成器函数
function* createArrayGenerator(arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[i]
}
// yield arr[0]
// yield arr[1]
// yield arr[2]
}
// namesGen生成器对象
let namesGen = createArrayGenerator(names)
console.log(namesGen.next());
console.log(namesGen.next());
console.log(namesGen.next());
console.log(namesGen.next());
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
// 使用生成器 生成某个范围的值
// 生成器函数
function* createRangeGenerator(start, end) {
for (let i = start; i <= end; i++) {
yield i
}
}
let rangeGen = createRangeGenerator(2, 5)
console.log(rangeGen.next());
console.log(rangeGen.next());
console.log(rangeGen.next());
console.log(rangeGen.next());
console.log(rangeGen.next());
console.log(rangeGen.next());
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
let names = ["码路", "漫漫", "前端"];
// 生成器函数
function* createArrayGenerator(arr) {
// yield语法糖
yield* arr
// for (let i = 0; i < arr.length; i++) {
// yield arr[i]
// }
// yield arr[0]
// yield arr[1]
// yield arr[2]
}
// namesGen生成器对象
let namesGen = createArrayGenerator(names)
console.log(namesGen.next());
console.log(namesGen.next());
console.log(namesGen.next());
console.log(namesGen.next());
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 四十三. 异步解决方案
<meta charset="utf-8">
<script>
// 异步解决方案 如果优雅地解决异步问题
// 前置内容:
// promise 迭代器 可迭代对象 生成器
// 异步的解决方案
// 1)回调函数 回调地狱
// 需求:
// 1.发送一次网络请求, 等到这次网络请求的结果 传学生的编号 得到 学生的姓名
// 2.发送第二次网络请求, 等待这次网络请求的结果 传学生的姓名 得到 学生的成绩
// 3.发送第三次网络请求, 等待这次网络请求的结果 传学生的成绩 得到 成绩的等级
function ajax(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data)
}, 2000)
})
}
// 一层屋嵌套 不优雅
function getData() {
// 第一次发送ajax
ajax("001").then(res1 => {
console.log("res1是学生的姓名");
// 第二次发送ajax
ajax(res1).then(res2 => {
console.log("res2是学生的成绩");
// 第三次发送ajax
ajax(res2).then(res3 => {
console.log("res3是学生的等级");
})
})
})
}
getData()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<meta charset="utf-8">
<script>
// 异步解决方案 如果优雅地解决异步问题
// 前置内容:
// promise 迭代器 可迭代对象 生成器
// 异步的解决方案
// 1)回调函数 回调地狱
// 2)then链
// 需求:
// 1.发送一次网络请求, 等到这次网络请求的结果 传学生的编号 得到 学生的姓名
// 2.发送第二次网络请求, 等待这次网络请求的结果 传学生的姓名 得到 学生的成绩
// 3.发送第三次网络请求, 等待这次网络请求的结果 传学生的成绩 得到 成绩的等级
function ajax(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data)
}, 2000)
})
}
// 一层屋嵌套 不优雅
function getData() {
// 第一次发送ajax
ajax("001").then(res1 => {
console.log("res1是学生的姓名");
return ajax(res1)
}).then(res2 => {
console.log("res2是学生的成绩");
return ajax(res2)
}).then(res3 => {
console.log("res3是学生的等级");
})
}
getData()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<meta charset="utf-8">
<script>
// 异步解决方案 如果优雅地解决异步问题
// 前置内容:
// promise 迭代器 可迭代对象 生成器
// 异步的解决方案
// 1)回调函数 回调地狱
// 2)then链
// 3)生成器函数(要学习生成器函数,必须学习迭代器)
// 需求:
// 1.发送一次网络请求, 等到这次网络请求的结果 传学生的编号 得到 学生的姓名
// 2.发送第二次网络请求, 等待这次网络请求的结果 传学生的姓名 得到 学生的成绩
// 3.发送第三次网络请求, 等待这次网络请求的结果 传学生的成绩 得到 成绩的等级
function ajax(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data)
}, 2000)
})
}
// 生成器函数
function* getData() {
let res1 = yield ajax("001")
let res2 = yield ajax(res1)
let res3 = yield ajax(res2)
console.log("res3:", "等级");
}
// 下面这一片代码能不能优化呢?
// TJ co
getData().next().value.then(res1 => {
console.log("res1是学生的姓名");
getData().next(res1).value.then(res2 => {
console.log("res2是学生的成绩");
getData().next(res2).value.then(res3 => {
console.log("res3是学生的等级");
// getData().next(res3)
})
})
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<meta charset="utf-8">
<script>
// 异步解决方案 如果优雅地解决异步问题
// 前置内容:
// promise 迭代器 可迭代对象 生成器
// 异步的解决方案
// 1)回调函数 回调地狱
// 2)then链
// 3)生成器函数(要学习生成器函数,必须学习迭代器)
// 4)终级方案 async和await
// 需求:
// 1.发送一次网络请求, 等到这次网络请求的结果 传学生的编号 得到 学生的姓名
// 2.发送第二次网络请求, 等待这次网络请求的结果 传学生的姓名 得到 学生的成绩
// 3.发送第三次网络请求, 等待这次网络请求的结果 传学生的成绩 得到 成绩的等级
function ajax(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(data)
}, 2000)
})
}
// 生成器函数
// async和await并不能把同步代码变成异步代码
// async和await 仅仅是生成器的语法糖
// koa1.x中 生成函数有大量使用
// react中 有一些中间件,也用到生成器
// 生成器是必学 迭代器 可迭代对象都需要学
async function getData() {
let res1 = await ajax("001")
console.log("res1是学生的姓名");
let res2 = await ajax(res1)
console.log("res2是学生的成绩");
let res3 = await ajax(res2)
console.log("res3是学生的等级");
}
getData()
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41