JavaScript进阶:手写代码挑战(二)

​🌈个人主页:前端青山
🔥系列专栏:JavaScript篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript手写代码篇

在现代Web开发中,JavaScript 是不可或缺的编程语言。掌握其核心功能和原理对于开发者至关重要。本文通过手写实现JavaScript的一些关键功能和算法,帮助读者深入理解其工作原理,提升编程技能。无论你是初学者还是有经验的开发者,都能从中受益。

目录

12 原型 继承 概念

13、instanceof

14 object.create

15 Object.is

16 new

17 浅拷贝

18 深拷贝

19 对象扁平化

20 数组扁平化

21 数组去重

22 promise

23 async/await

24 并发

25 发布/订阅

26 防抖

27 节流

28 柯里化

29 vue Reactive ​


12 原型 继承 概念

1. 继承
例举几种比较常用的继承方式
/*** 使用 extends 继承*/
​
// 继承类
class Vehicle {}
class Bus extends Vehicle {}
​
let b = new Bus();
console.log(b instanceof Bus); // true
console.log(b instanceof Vehicle); // true
​
​
// 继承普通构造函数
function Person() {}
class Engineer extends Person {}
​
let e = new Engineer();
console.log(e instanceof Engineer); // true
console.log(e instanceof Person); // true
​
​
/*** 寄生式组合继承*/
function Person(name) {this.name = name;
}
function Man(name, age) {Person.call(this, name, age);this.age = age;
}
Man.prototype = Object.create(Person.prototype);
Man.prototype.constructor = Man;
​
const man = new Man('mxin', 18);
console.log(man instanceof Man); // true
console.log(man instanceof Person); // true

13、instanceof

/*** 模拟 instanceof* 判断 obj.__proto__ 和 __constructor.prototype 是否相等* @param {object} obj 实例对象* @param {function} __constructor 构造函数*/
function __instanceof(obj, __constructor) {const prototype = __constructor.prototype;obj = Object.getPrototypeOf(obj);
​while (true) {if (obj === null) return false;if (obj === prototype) return true;obj = Object.getPrototypeOf(obj);}
}
​
// ------------------------------ 测试 ------------------------------
​
function C() {}
function D() {}
​
const o = new C();
​
// __instanceof()
console.log('__instanceof()');
​
console.log(__instanceof(o, C));
console.log(__instanceof(o, D));
console.log(__instanceof(o, Object));
​
// instanceof
console.log('instanceof');
​
console.log(o instanceof C);
console.log(o instanceof D);
console.log(o instanceof Object);

14 object.create

/*** 模拟 Object.create* 创建一个新对象,使用现有的对象来提供新创建的对象的__proto__* @param {object} prototype 新创建对象的原型对象,为 null 时 只能使用 Object.create()* @param {object} properties 访问器描述符,同 Object.defineProperties 第二个参数* @returns {object}*/
function __create(prototype, properties) {if (typeof prototype !== 'object') throw new TypeError('Error');
​function Constructor() {}Constructor.prototype = prototype;
​const obj = new Constructor();
​if (prototype) obj.constructor = Constructor;
​// 设置访问器描述符if (properties) {if (typeof properties !== 'object') throw TypeError('Error');Object.defineProperties(obj, properties);}
​return obj;
}
​
// ------------------------------ 测试 ------------------------------
​
const person = {isHuman: false,printIntroduction: function () {console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);},
};
​
// __create()
console.log('__create()');
​
const __me = __create(person);
__me.name = '__mxin';
__me.isHuman = true;
__me.printIntroduction();
​
// Object.create()
console.log('Object.create()');
​
const me = Object.create(person);
me.name = 'mxin';
me.isHuman = true;
me.printIntroduction();
​
// 目前创建纯净空对象只有 Object.create(null) 可行,无法模拟
const emptyObj = Object.create(null);
console.log(emptyObj);
// {}
//    No properties

15 Object.is

  • == 运算不同,== 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 "" == false 判断为 true), 而 Object.is不会强制转换两边的值

  • === 运算也不相同, === 运算符 (也包括 == 运算符) 将数字 -0+0 视为相等 ,而将Number.NaNNaN 视为不相等

/*** 模拟 Object.is* 判断两个值是否为同一个值* 1. 都是 undefined* 2. 都是 null* 3. 都是 true 或 false* 4. 都是相同长度的字符串且相同字符按相同顺序排列* 5. 都是相同对象(意味着每个对象有同一个引用)* 6. 都是数字且*    a. 都是 +0*    b. 都是 -0*    c. 都是 NaN*    d. 或都是非零而且非 NaN 且为同一个值* @param {*} x* @param {*} y*/
function __is(x, y) {if (x === y) {return x !== 0 || 1 / x === 1 / y;} else {return x !== x && y !== y;}
}
​
// ------------------------------ 测试 ------------------------------
​
// __is()
console.log('__is()');
​
console.log(`__is('foo', 'foo'): ${__is('foo', 'foo')}`); // true
console.log(`__is('foo', 'bar'): ${__is('foo', 'bar')}`); // false
​
const __foo = { a: 1 };
const __bar = { a: 1 };
console.log(`__is(__foo, __foo): ${__is(__foo, __foo)}`); // true
console.log(`__is(__foo, __bar): ${__is(__foo, __bar)}`); // false
console.log(`__is(window, window): ${__is(window, window)}`); // true
console.log(`__is([], []): ${__is([], [])}`); // false
console.log(`__is(null, null): ${__is(null, null)}`); // true
​
// 特例
console.log(`__is(0, -0): ${__is(0, -0)}`); // false
console.log(`__is(0, +0): ${__is(0, +0)}`); // true
console.log(`__is(-0, -0): ${__is(-0, -0)}`); // true
// console.log(`__is(NaN, 0 / 0): ${__is(NaN, 0 / 0)}`); // true
​
​
// Object.is()
console.log('Object.is()');
​
console.log(`Object.is('foo', 'foo'): ${Object.is('foo', 'foo')}`); // true
console.log(`Object.is('foo', 'bar'): ${Object.is('foo', 'bar')}`); // false
​
const foo = { a: 1 };
const bar = { a: 1 };
console.log(`Object.is(foo, foo): ${Object.is(foo, foo)}`); // true
console.log(`Object.is(foo, bar): ${Object.is(foo, bar)}`); // false
console.log(`Object.is(window, window): ${Object.is(window, window)}`); // true
console.log(`Object.is([], []): ${Object.is([], [])}`); // false
console.log(`Object.is(null, null): ${Object.is(null, null)}`); // true
​
// 特例
console.log(`Object.is(0, -0): ${Object.is(0, -0)}`); // false
console.log(`Object.is(0, +0): ${Object.is(0, +0)}`); // true
console.log(`Object.is(-0, -0): ${Object.is(-0, -0)}`); // true
console.log(`Object.is(NaN, 0 / 0): ${Object.is(NaN, 0 / 0)}`); // true

16 new

/*** 模拟 new* 1. 创建原型为 constructor.prototype 的新对象 obj* 2. 执行构造函数,this 指向 obj* 3. 判断构造函数返回值是否为对象,是就返回此对象* 4. 构造函数无返回值返回 obj* @param {function} constructor* @param  {...any} args* @returns {object}*/
function __new(constructor, ...args) {if (typeof constructor !== 'function') throw new TypeError('Error');
​// 创建一个空对象,指定原型为constructor.prototypeconst obj = Object.create(constructor.prototype);
​// 执行构造函数,绑定thisconst result = constructor.apply(obj, args);
​// 如果构造函数返回值是一个对象,那么返回该对象, 如果没有就返回 objreturn result && result instanceof Object ? result : obj;
}
​
// ------------------------------ 测试 ------------------------------
​
function Person(name, age) {this.name = name;this.age = age;
}
​
// __new
console.log('__new');
const __mxin = __new(Person, '__mxin', 18);
console.log(__mxin);
// Person {name: "__mxin", age: "18"}
//     age: "18"
//     name: "__mxin"
//     __proto__:
//         constructor: ƒ Person(name, age)
//         __proto__: Object
​
// new
console.log('new');
const mxin = new Person('mxin', 18);
console.log(mxin);
// Person {name: "mxin", age: "18"}
//     age: "18"
//     name: "mxin"
//     __proto__:
//         constructor: ƒ Person(name, age)
//         __proto__: Object

17 浅拷贝

几种常用方式:

  1. 自定义循环

  2. 展开运算符

  3. Object.assign()

/*** 浅拷贝,无脑循环* @param {*} targetObj*/
function shallowClone(targetObj) {const resObj = {};for (let key in targetObj) {resObj[key] = targetObj[key];}return resObj;
}
​
// ------------------------------ 测试 ------------------------------
​
console.log('shallowClone()');
​
const shallowObj = {name: 'mxin',age: 18,
};
​
/*** 自定义方法*/
const a = shallowClone(shallowObj);
a.name = '__mxin';
a.age = 20;
​
console.log('a', a);
// {name: "__mxin", age: 20}
//   age: 20
//   name: "__mxin"
​
/*** 拓展运算符*/
const b = { ...a };
b.name = '____mxin';
b.age = 22;
​
console.log('b', b);
// {name: "____mxin", age: 22}
//   age: 22
//   name: "____mxin"
​
/*** Object.assign()*/
const c = Object.assign({}, shallowObj)
c.name = '______mxin';
c.age = 24;
​
console.log('c', c);
// {name: "______mxin", age: 24}
//   age: 24
//   name: "______mxin"
​
// 不影响原有对象
console.log('shallowObj', shallowObj);
// {name: "mxin", age: 18}
//   age: 18
//   name: "mxin"

18 深拷贝

/*** 深拷贝* 深层克隆对象结构* @param {object} target* @returns {object}*/
function deepClone(target) {// 如果不是对象,直接返回本身if (!isObject(target) || target === null) return target;
​// 参数类型校验情况还有很多,没有覆盖全面,可以后期拓展if (target instanceof Date) return new Date(target);if (target instanceof RegExp) return new RegExp(target);
​const obj = {};const stack = [{parent: obj,key: null,data: target,},];
​while (stack.length) {const node = stack.pop();const parent = node.parent;const key = node.key;const data = node.data;
​let res = key ? (parent[key] = {}) : parent;
​for (const k in data) {if (data.hasOwnProperty(k)) {if (isObject(data[k])) {stack.push({parent: res,key: k,data: data[k],});} else {res[k] = data[k];}}}}
​return obj;
}
​
/*** 判断 target 是否为对象* @param {*} target*/
function isObject(target) {return Object.prototype.toString.call(target) === '[object Object]';
}
// ------------------------------ 测试 ------------------------------
​
console.log('deepClone()');
​
const deepObj = {e: {f: {g: {h: 1,},},},i: {j: {k: {l: 2,},},},
};
​
const d = deepClone(deepObj);
d.e.f.g.h = 2;
d.i.j.k.l = 4;
​
console.log('d', d);
​
// 不影响原有对象
console.log('deepObj', deepObj);

19 对象扁平化

/*** 对象扁平化* 将多层嵌套的 key 合并* @param {object} target* @param {string} tempKey* @param {object} res* @returns {object}*/
function flattenObject(target, tempKey = '', res = {}) {// 使用 Object.entries() 将键值对转换成数组,确保 key 与 val 的对应关系for (const [key, val] of Object.entries(target)) {// 如果 val 是对象,保存合并后的 key 进行递归if (isObject(val)) {const tmp = tempKey + key + '.';flattenObject(val, tmp, res);} else {// 当 val 不是对象,合并 key 并对结果对象赋值const tmp = tempKey + key;res[tmp] = val;}}return res;
}
​
/*** 判断 target 是否为对象* @param {*} target*/
function isObject(target) {return Object.prototype.toString.call(target) === '[object Object]';
}
​
// ------------------------------ 测试 ------------------------------
​
console.log('flattenObject()');
​
const object = {d: {e: {f: {g: {h: 1,},},},i: {j: {k: {l: 2,},},},},
};
​
console.log(flattenObject(object));
// {
//   d.e.f.g.h: 1
//   d.i.j.k.l: 2
// }

20 数组扁平化

 几种常用方式:
递归
Array.prototype.flat()
Array.prototype.reduce()
/*** 数组扁平化* 判断数组中元素类型,如果是数组类型就递归,否则直接 push 到 res 中* @param {array} target* @param {array} res* @returns {array}*/
function flattenArray(target, res = []) {for (const val of target) {if (Array.isArray(val)) {flattenArray(val, res);} else {res.push(val);}}return res;
}
​
/*** 使用 Array.prototype.reduce()* @param {array} target*/
function flattenArrayByReduce(target) {const initPre = [];return target.reduce((pre, current) =>pre.concat(Array.isArray(current) ? flattenArrayByReduce(current) : current),initPre);
}
​
// ------------------------------ 测试 ------------------------------
​
console.log('flattenArray()');
​
const array = [[0], 1, [2, [3, [4, [5, [6]]]]], [7, [8]]];
​
/*** 递归*/
console.log(flattenArray(array));
// [0, 1, 2, 3, 4, 5, 6, 7, 8]
​
/*** Array.prototype.flat()*/
console.log(array.flat(Number.MAX_SAFE_INTEGER));
// [0, 1, 2, 3, 4, 5, 6, 7, 8]
​
/*** Array.prototype.reduce()*/
console.log(flattenArrayByReduce(array));
// [0, 1, 2, 3, 4, 5, 6, 7, 8]
##

21 数组去重

  • 使用 set

console.log([...new Set(array)]);
  • 使用对象,或者将对象换成 map ,需要注意数组中元素的类型

/*** 数组去重* 基于对象实现,也可以使用 Map* @param {array} target* @returns {array}*/
function removeDuplicate(target) {const temp = {};for (let i = 0; i < target.length; i++) {const item = target[i];if (Object.prototype.toString.call(item) !== '[object Object]' &&Object.prototype.toString.call(item) !== '[object Function]' &&Object.prototype.toString.call(item) !== '[object Symbol]' &&Object.prototype.toString.call(item) !== '[object Array]') {if (temp.hasOwnProperty(item)) {target[i] = target[target.length - 1];target.length--;i--;}}temp[item] = item;}return target;
}
​
// ------------------------------ 测试 ------------------------------
​
console.log('removeDuplicate()');
​
const array = [1,1,'2','2',true,true,false,false,undefined,undefined,null,null,Symbol('3'),Symbol('3'),{},{},[],[],
];
​
console.log(removeDuplicate(array));

22 promise

  • Promise

    • resolve

    • reject

    • then

    • catch

    • finally

  • Promise.resolve

  • Promise.reject

  • Promise.all

  • promise.race

const isFunction = variable => typeof variable === 'function';
​
// 定义Promise的三种状态常量
const PENDING = 'pending';
const RESOLVE = 'resolved';
const REJECTED = 'rejected';
​
class __Promise {constructor(fn) {this.__status = PENDING;// 储存 value,用于 __then 返回this.__value = null;// 失败队列,在 __then 时注入,resolve 时触发this.__rejectedQueues = [];// 成功队列,在 __then 时注入,resolve 时触发this.__resolvedQueues = [];
​try {fn(this.__resolve, this.__reject);} catch (err) {this.__reject(err);}}
​__resolve = val => {const run = () => {if (this.__status !== PENDING) return;this.__status = RESOLVE;
​// 依次执行成功队列中的函数,并清空队列const runResolved = value => {let cb;while ((cb = this.__resolvedQueues.shift())) {cb(value);}};
​// 依次执行失败队列中的函数,并清空队列const runRejected = error => {let cb;while ((cb = this.__rejectedQueues.shift())) {cb(error);}};
​/** 如果 resolve 的参数为 Promise 对象,* 则必须等待该 Promise 对象状态改变后当前 Promsie 的状态才会改变* 且状态取决于参数 Promsie 对象的状态*/if (val instanceof __Promise) {val.__then(value => {this.__value = value;runResolved(value);},err => {this.__value = err;runRejected(err);});} else {this.__value = val;runResolved(val);}};
​// 异步调用setTimeout(run);};
​__reject = err => {if (this.__status !== PENDING) return;
​const run = () => {this.__status = REJECTED;this.__value = err;let cb;while ((cb = this.__rejectedQueues.shift())) {cb(err);}};
​setTimeout(run);};
​__then(onResolved, onRejected) {const { __value, __status } = this;
​return new __Promise((onResolvedNext, onRejectedNext) => {const resolved = value => {try {if (!isFunction(onResolved)) {onResolvedNext(value);} else {const res = onResolved(value);
​if (res instanceof __Promise) {// 如果当前回调函数返回__Promise对象,必须等待其状态改变后在执行下一个回调res.__then(onResolvedNext, onRejectedNext);} else {// 否则会将返回结果直接作为参数,传入下一个 __then 的回调函数,并立即执行下一个 __then 的回调函数onResolvedNext(res);}}} catch (err) {onRejectedNext(err);}};
​const rejected = error => {try {if (!isFunction(onRejected)) {onRejectedNext(error);} else {const res = onRejected(error);
​if (res instanceof __Promise) {res.__then(onResolvedNext, onRejectedNext);} else {onResolvedNext(res);}}} catch (err) {onRejectedNext(err);}};
​if (__status === PENDING) {this.__resolvedQueues.push(resolved);this.__rejectedQueues.push(rejected);}
​if (__status === RESOLVE) resolved(__value);
​if (__status === REJECTED) rejected(__value);});}
​__catch(onRejected) {return this.__then(null, onRejected);}
​__finally(cb) {return this.__then(value => __Promise.resolve(cb()).__then(() => value),reason =>__Promise.resolve(cb()).__then(() => {throw new Error(reason);}));}
​static resolve(value) {// 如果参数是 __Promise 实例,直接返回这个实例if (value instanceof __Promise) return value;return new __Promise(resolve => resolve(value));}
​static reject(value) {return new __Promise((resolve, reject) => reject(value));}
​static all(list) {return new __Promise((resolve, reject) => {const values = [];let count = 0;
​for (const [i, p] of list.entries()) {// 数组参数如果不是 __Promise 实例,先调用 __Promise.resolvethis.resolve(p).__then(res => {values[i] = res;count++;// 所有状态都变成 resolved 时返回的 __Promise 状态就变成 resolvedif (count === list.length) resolve(values);},err => {// 有一个被 rejected 时返回的 __Promise 状态就变成 rejectedreject(err);});}});}
​static race(list) {return new __Promise((resolve, reject) => {list.forEach(p => {this.resolve(p).__then(res => {resolve(res);},err => {reject(err);});});});}
}
​
// ------------------------------ 测试 ------------------------------
console.log('class __Promise {}');
​
const p1 = new __Promise((resolve, reject) =>setTimeout(() => {resolve('mxin');}, 500)
);
const p2 = new __Promise((resolve, reject) =>setTimeout(() => {resolve('__mxin');}, 200)
);
const p3 = new __Promise((resolve, reject) => {setTimeout(() => {reject(new Error('mxin3'));}, 100);
});
​
// 测试 __resolve __then __finally
new __Promise((resolve, reject) => {resolve('mxin');
}).__then(res => {console.log('__resolve:', res);}).__finally(() => {console.log('__resolve finally');});
​
// 测试 __reject __catch __finally
new __Promise((resolve, reject) => {reject(new Error());
}).__catch(e => {console.log('__reject:', e);}).__finally(() => {console.log('__reject finally');});
​
// 测试 static resolve
__Promise.resolve('mxin').__then(res => console.log('static resolve:', res)).__finally(() => console.log('static resolve finally'));
​
// 测试 static reject
__Promise.reject(new Error()).__catch(res => console.log('static reject:', res)).__finally(() => console.log('static reject finally'));
​
// 测试 all,可添加 p3 测试 rejected 状态
__Promise.all([p1, p2]).__then(res => console.log('all resolve:', res)).__catch(e => console.log('all reject', e)).__finally(() => console.log('all finally'));
​
// 测试 race,速度快的优先返回并结束, 添加 p3 优先 reject
__Promise.race([p1, p2]).__then(res => console.log('race resolve:', res)).__catch(e => console.log('race reject', e)).__finally(() => console.log('race finally'));

23 async/await

const NEXT = 'next';
const THROW = 'throw';
/*** 模拟 async 函数* 1.generator 分割代码片段* 2.使用一个函数让其自迭代* 3.使用 promise 将 yield 包裹起来* 4.执行下一步的时机由 promise 来控制* @param {*} fn*/
function __async(fn) {return function () {// 获取迭代器实例const gen = fn.apply(this, arguments);
​return new Promise((resolve, reject) => {// 执行下一步function _next(value) {__step(gen, resolve, reject, _next, _throw, NEXT, value);}// 抛异常function _throw(err) {__step(gen, resolve, reject, _next, _throw, THROW, err);}// 首次触发_next(void 0);});};
}
​
/*** 执行迭代步骤,处理下次迭代结果* 1.将所有值promise化* 2.当 promise 执行完之后再执行下一步* 3.递归调用 next 函数,直到 done == true*/
function __step(gen, resolve, reject, _next, _throw, key, arg) {try {var info = gen[key](arg);var value = info.value;} catch (error) {return reject(error);}// 迭代完成if (info.done) {resolve(value);} else {Promise.resolve(value).then(_next, _throw);}
}
​
// ------------------------------ 测试 ------------------------------
console.log('async');
​
__async(function* () {const e = yield new Promise(resolve =>setTimeout(() => {resolve('e');}, 1000));const a = yield Promise.resolve('a');const d = yield 'd';const b = yield Promise.resolve('b');const c = yield Promise.resolve('c');return [a, b, c, d, e];
})().then(res => console.log(res) // ['a', 'b', 'c', 'd', 'e']
);

24 并发

/*** 异步分片处理并发* 1.通过 limitNum 限制并发的 promise 数量* 2.临时结果保存到 resArr 中* 3.start 返回 promise,全部执行完毕 finally 中 resolve 最终结果*/
class Limit {constructor(limitNum, promiseList) {this.resArr = [];this.handling = 0;this.resolvedNum = 0;this.limitNum = limitNum;this.promiseList = promiseList;this.runTime = this.promiseList.length;}
​handle(promise) {console.log(promise, this.handling);return new Promise((resolve, reject) => {promise.then(res => resolve(res)).catch(e => reject(e));});}
​start() {const __this = this;return new Promise(resolve => {const run = () => {if (!__this.promiseList.length) return;__this.handling += 1;__this.handle(__this.promiseList.shift()).then(res => {__this.resArr.push(res);}).catch(e => {const error = new Error(e);__this.resArr.push(error);}).finally(() => {__this.handling -= 1;__this.resolvedNum += 1;if (__this.resolvedNum === __this.runTime) {resolve(__this.resArr);}run();});};
​for (let i = 1; i <= __this.limitNum; i++) {run();}});}
}
​
// ------------------------------ 测试 ------------------------------
console.log('Limit');
​
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1);}, 1000);
});
const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve(2);}, 1000);
});
const p3 = new Promise((resolve, reject) => {setTimeout(() => {reject(3);}, 2000);
});
const p4 = new Promise((resolve, reject) => {setTimeout(() => {resolve(4);}, 2000);
});
const p5 = new Promise((resolve, reject) => {setTimeout(() => {resolve(5);}, 3000);
});
const p6 = new Promise((resolve, reject) => {setTimeout(() => {resolve(6);}, 3000);
});
const promiseList = [p1, p2, p3, p4, p5, p6];
​
const limit = new Limit(2, promiseList);
​
limit.start().then(res => {console.log(res);
});

25 发布/订阅

*** 事件订阅/发布* 1.on 收集 key 对应的回调函数依赖关系,存入 eventList* 2.emit 根据第一个参数判断 key 值,并执行其函数依赖* 3.remove 根据 key 值清空依赖*/
class __Event {constructor() {this.eventList = [];}
​on(key, fn) {if (!this.eventList[key]) this.eventList[key] = [];this.eventList[key].push(fn);}
​emit() {const key = [].shift.call(arguments);const fns = this.eventList[key];
​if (!fns || fns.length === 0) return false;
​for (const fn of fns) {fn.apply(this, arguments);}}
​remove(key) {if (!this.eventList[key]) return false;this.eventList[key] = null;delete this.eventList[key];}
}
​
// ------------------------------ 测试 ------------------------------
// Event
console.log('Event');
​
const __event = new __Event();
​
__event.on('name', val => {console.log(`info: ${val}`);// info: mxin
});
​
__event.on('name', val => {console.log(`info2: ${val}`);// info2: mxin
});
​
// 触发事件,上面两个回调执行对应代码
__event.emit('name', 'mxin');
​
// 移除事件
__event.remove('name');
​
// 事件被移除,不再触发
__event.emit('name', 'mxin');

26 防抖

/*** 防抖* 事件高频触发,间隔 wait 时长执行回调* @param {*} fn* @param {*} wait*/
function debounce(fn, wait) {let timeout;return function () {let __this = this,args = arguments;if (timeout) clearTimeout(timeout);timeout = setTimeout(() => {fn.apply(__this, args);}, wait);};
}
​
// ------------------------------ 测试 ------------------------------
​
// debounce()
console.log('debounce()');
​
window.onresize = debounce(function () {console.log('改变窗口大小完毕 1000ms 后触执行');
}, 1000);

27 节流

/*** 节流* 高频事件触发,间隔 delay 时间执行一次回调* @param {*} fn* @param {*} delay*/
function throttle(fn, delay) {const prevTime = Date.now();return function () {const curTime = Date.now();if (curTime - prevTime > delay) {fn.apply(this, arguments);prevTime = curTime;}};
}
​
// ------------------------------ 测试 ------------------------------
​
// throttle()
console.log('throttle()');
​
window.onresize = throttle(function () {console.log('间隔 1000ms 执行一次');
}, 1000);

28 柯里化

/*** 柯里化* 把接受多个参数的函数变换成接受一个单一参数的函数* 并返回接受余下的参数且返回结果的新函数*/
function curry() {const args = [...arguments];
​const fn = function () {args.push(...arguments);return fn;};
​fn.toString = () => {return args.reduce((pre, current) => pre + current);};return fn;
}
​
// ------------------------------ 测试 ------------------------------
​
// curry
console.log('curry()');
​
console.log(curry(1)(2)(3)); // 6
console.log(curry(1, 2, 3)(4)); // 10
console.log(curry(1)(2)(3)(4)(5)); // 15
console.log(curry(2, 6)(1)); // 9

29 vue Reactive ​

const reactiveMap = new WeakMap();
const targetMap = new WeakMap();
const effectStack = [];
​
/*** 副作用函数* @param {*} fn*/
function effect(fn) {try {// 将需要执行的effect入栈effectStack.push(fn);
​// 执行该effect,进入proxy的get拦截return fn();} finally {// 依赖收集完毕及所有get流程走完,当前effect出栈effectStack.pop();}
}
​
/*** 依赖收集* @param {*} target* @param {*} key*/
function track(target, key) {// 初始化依赖Maplet depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}
​// 第二层依赖使用Set存放key对应的effectlet dep = depsMap.get(key);if (!dep) {targetMap.get(target).set(key, (dep = new Set()));}
​// 取当前栈中的effect存入第二层依赖中const activeEffect = effectStack[effectStack.length - 1];activeEffect && dep.add(activeEffect);
}
​
/*** 触发响应,执行effect* @param {*} target* @param {*} key*/
function trigger(target, key) {const depsMap = targetMap.get(target);if (depsMap) {const effects = depsMap.get(key);effects && effects.forEach(run => run());}
}
​
/*** 定义响应式对象,返回proxy代理对象* @param {*} object*/
function reactive(object) {if (reactiveMap.has(object)) return reactiveMap.get(object);
​const proxy = new Proxy(object, handlers);
​reactiveMap.set(object, proxy);return proxy;
}
​
/*** 处理器对象,定义捕获器*/
const handlers = {set(target, key) {Reflect.set(...arguments);trigger(target, key);},get(target, key) {track(target, key);return typeof target[key] === 'object'? reactive(target[key]): Reflect.get(...arguments);},
};
​
/*** 计算属性* @param {*} fn*/
function computed(fn) {return {get value() {return effect(fn);},};
}
​
module.exports = {effect,reactive,computed,
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/455307.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统基础-进程间通信(5)_模拟实现命名管道和共享内存

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux系统基础-进程间通信(5)_模拟实现命名管道和共享内存 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…

Mac 使用 zsh 终端提示 zsh: killed 的问题

我的脚本的内容为&#xff1a; #!/bin/bashset -epids$(ps -ef | grep consul | grep -v grep | awk {print $2})for pid in $pids; doecho "kill process: $pid"kill -9 $pid donecd $(dirname $0)nohup ./consul agent -dev > nohup.log &可以看到这是一个…

阿里云项目启动OOM问题解决

问题描述 随着项目业务的增长&#xff0c;系统启动时内存紧张&#xff0c;每次第一次启动的时候就会出现oom第二次或者第n的时候&#xff0c;就启动成功了。 带着这个疑问&#xff0c;我就在阿里云上提交了工单&#xff0c;咨询为什么第一次提交失败但是后面却能提交成功尼&a…

Matlab学习01-矩阵

目录 一&#xff0c;矩阵的创建 1&#xff0c;直接输入法创建矩阵 2&#xff0c;利用M文件创建矩阵 3&#xff0c;利用其它文本编辑器创建矩阵 二&#xff0c;矩阵的拼接 1&#xff0c;基本拼接 1&#xff09; 水平方向的拼接 2&#xff09;垂直方向的拼接 3&#xf…

shell脚本-函数

文章目录 一、函数介绍什么是函数、为什么使用函数、如何使用函数 二、shell脚本中如何定义函数Way1Way2Way3 三、shell脚本中如何调用函数四、shell脚本中使用内置变量(1、#、?、2等等)五、函数的返回值、shell脚本中函数的返回值函数的返回值概念shell脚本中函数的返回值ret…

梦金园三闯港交所上市:年营收200亿元,靠加盟模式取胜

近日&#xff0c;梦金园黄金珠宝集团股份有限公司&#xff08;以下简称“梦金园”&#xff09;向港交所递交IPO申请&#xff0c;中信证券为其独家保荐人。贝多财经了解到&#xff0c;这已经是梦金园第三次向港股发起冲击&#xff0c;此前曾于2023年9月、2024年4月两度递表。 继…

刷题 - 图论

1 | bfs/dfs | 网格染色 200. 岛屿数量 访问到马上就染色&#xff08;将visited标为 true)auto [cur_x, cur_y] que.front(); 结构化绑定&#xff08;C17&#xff09;也可以不使用 visited数组&#xff0c;直接修改原始数组时间复杂度: O(n * m)&#xff0c;最多将 visited 数…

Deepinteraction 深度交互:通过模态交互的3D对象检测

一.前提 为什么要采用跨模态的信息融合? 点云在低分辨率下提供必要的定位和几何信息&#xff0c;而图像在高分辨率下提供丰富的外观信息。 -->因此必须采用跨模态的信息融合 提出的原因? 传统的融合办法可能会由于信息融合到统一表示中的不太完美而丢失很大一部分特定…

磁珠的工作原理:【图文讲解】

1&#xff1a;什么是磁珠 磁珠是一种被动组件&#xff0c;用来抑制电路中的高频噪声。磁珠是一种特别的扼流圈&#xff0c;其成分多半为铁氧体&#xff0c;利用其高频电流产生的热耗散来抑制高频噪声。磁珠有时也称为磁环、EMI滤波器、铁芯等。 磁珠是滤波常用的器件&#xf…

SpringMVC常用注解

RequestMapping接口的映射&#xff0c;可以将HTTP请求映射到控制器方法上&#xff0c;通过这个注解使用不同的映射&#xff0c;就可以区分不同的控制器&#xff0c;其中RequestMapping中还有不同的属性&#xff0c;比如method&#xff0c;params&#xff0c;produces等在这里我…

快速搭建SpringBoot3+Prometheus+Grafana

快速搭建SpringBoot3PrometheusGrafana 一、搭建SpringBoot项目 1.1 创建SpringBoot项目 1.2 修改pom文件配置 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://…

25年山东高考报名时间为10月23日-29日

今日&#xff0c;山东省招生考试院发布关于《山东省2025年普通高等学校招生考试报名工作的通知》 其中高考报名时间定为&#xff1a;2024年10月23日29日&#xff08;每天9&#xff1a;0018&#xff1a;00&#xff09; 资格审查时间为&#xff1a;10月30日~11月11日 网上缴费时间…

Android问题记录 - 适配Android Studio Ladybug/Java 21/AGP 8.0

文章目录 前言开发环境问题描述问题分析1. 适配Java 212. 适配AGP 8.0 解决方案补充内容最后 前言 Android Studio版本从Koala Feature Drop升级到Ladybug&#xff0c;出现了一系列报错。 开发环境 Flutter: 3.24.3Android Studio: 2024.2.1 Patch 1Java: 21.0.3Gradle: 7.4…

FPGA实现PCIE采集电脑端视频转SFP光口万兆UDP输出,基于XDMA+GTX架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案10G Ethernet Subsystem实现万兆以太网物理层方案 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频PCIE视频采集QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存UDP视频组包发送UDP协议栈MAC…

高效改进!防止DataX从HDFS导入关系型数据库丢数据

高效改进&#xff01;防止DataX从HDFS导入关系型数据库丢数据 针对DataX在从HDFS导入数据到关系型数据库过程中的数据丢失问题&#xff0c;优化了分片处理代码。改动包括将之前单一分片处理逻辑重构为循环处理所有分片&#xff0c;确保了每个分片数据都得到全面读取和传输&…

Git文件操作指令和文件状态

一、Git 文件操作指令 1、查看指定文件的状态 git status [filename] 我们在新创建且初始化过后的 git 仓库中新建一个 文件&#xff0c;然后在 git 的命令行中输入此指令后&#xff0c;就可以看到 的状态&#xff1a; 在此显示的是 Untracked 的状态&#xff0c;也就是未…

visual studio设置修改文件字符集方法

该方法来自网文&#xff0c;特此记录备忘。 添加两个组件&#xff0c;分别是Force UTF-8,FileEncoding。 截图如下&#xff1a; 方法如下&#xff1a;vs中点击“扩展”->“管理扩展”&#xff0c;输入utf搜索&#xff0c;安装如下两个插件&#xff0c;然后重启vs&#xf…

【pytorch DistributedDataParallel 及amp 使用过程遇到的问题记录 】

目录 环境问题单机多卡时&#xff1a;超时错误部分报错内容:解决方法: 存在没有使用梯度的参数报错内容:解决方法:方法1 找到不参与梯度计算的层**且**没有用处的层&#xff0c;删除方法2 DistributedDataParallel 增加参数:find_unused_parameters True DDP 训练时第一个batc…

2 两数相加

解题思路&#xff1a; \qquad 这道题可以用模拟很直观的解决&#xff0c;模式加法的计算过程&#xff0c;只不过套了一层链表的外衣。题目给出的数字在链表中是按照逆序排列的&#xff0c;即链表头节点的值代表相加数字的个位&#xff0c;这样只需要从链表头开始计算加法即可得…

系统登录接口文档Demo

接口描述 该接口用于用户登录验证。通过用户名和密码进行身份验证&#xff0c;成功后返回一个用于后续请求的认证 token。这个 token 是访问受保护资源的凭证。 时序图&#xff1a; 登录请求&#xff1a; 登录查询接口: POST {url}/api/user/login 请求体: {"username…