JavaScript 代码片段
第一部分【Common】
Polyfills
第二部分【Fast】
第三部分【Util】
本文档使用 MrDoc 发布
-
+
首页
第一部分【Common】
## 管道链 ```js function compose(...fn) { return fn.reduce((result, it) => { return (...args) => { return result(it(...args)) } }, (it) => it) } ``` 用法: ```js function fn1(x) { return x + 1; } function fn2(x) { return x + 2; } function fn3(x) { return x + 3; } function fn4(x) { return x + 4; } const a = compose(fn1, fn2, fn3, fn4); console.log(a(1)); // 1+4+3+2+1=11 ``` ## instanceOf 方法 1: 递归法 ```js const instanceOf = (obj, func) => { if (!(obj && ["object", "function"].includes(typeof obj))) { return false; } let proto = Object.getPrototypeOf(obj); if (proto === func.prototype) { return true; } else if (proto === null) { return false; } else { return instanceOf(proto, func); } }; ``` 方法 2: 循环法 ```js const instanceOf = (obj, func) => { if (!(obj && ["object", "function"].includes(typeof obj))) { return false; } let proto = obj; while ((proto = Object.getPrototypeOf(proto))) { if (proto === null) { return false; } else if (proto === func.prototype) { return true; } } return false; }; ``` 用法: ```js let Fn = function () {}; let p1 = new Fn(); console.log(instanceOf({}, Object)); // true console.log(instanceOf(p1, Fn)); // true console.log(instanceOf({}, Fn)); // false console.log(instanceOf(null, Fn)); // false console.log(instanceOf(1, Fn)); // false console.log(instanceOf(function a() {}, Function)); // true ``` ## deepFlat 方法 1: 递归法 ```js const flat = (array) => { return array.reduce((result, it) => { return result.concat(Array.isArray(it) ? flat(it) : it) }, []) } ``` 方法 2: js 原生法 ```js const flat = (array) => { return array.flat(Infinity) } ``` 方法 3: 循环法 ```js const flat = (array) => { const result = [] const stack = [ ...array ] while (stack.length !== 0) { const val = stack.pop() if (Array.isArray(val)) { stack.push(...val) } else { result.unshift(val) } } return result } ``` ## simulateSetInterval ```js const simulateSetInterval = (func, timeout) => { let timer = null; const interval = () => { timer = setTimeout(() => { func(); interval(); }, timeout); }; interval(); return () => clearTimeout(timer); }; ``` 用法: ```js const cancel = simulateSetInterval(() => { console.log(1); }, 300); setTimeout(() => { cancel(); }, 1000); ``` ## simulateSetTimeout ```js const simulateSetTimeout = (fn, timeout) => { let timer = null; timer = setInterval(() => { clearInterval(timer); fn(); }, timeout); return () => clearInterval(timer); }; ``` 用法: ```js const cancel = simulateSetTimeout(() => { console.log(1); }, 1000); setTimeout(() => { cancel(); }, 1100); ``` ## call ```js Function.prototype.call = function (ctx, ...args) { if (!ctx) { ctx = typeof window !== "undefined" ? window : global; } // 暴露处理 ctx 有可能传非对象 ctx = Object(ctx); const fnName = Symbol("key"); ctx[fnName] = this; const result = ctx[fnName](...args); delete ctx[fnName]; return result; }; ``` 用法: ```js let fn = function (name, sex) { console.log(this, name, sex); }; fn.call("", "前端胖头鱼", "boy"); // { name: '前端胖头鱼', sex: 'boy', [Symbol(key)]: [Function: fn] } 前端胖头鱼 boy fn.call({ name: "前端胖头鱼", sex: "boy" }, "前端胖头鱼", "boy"); ``` ## apply ```js Function.prototype.apply = function (ctx, args) { if (!ctx) { ctx = typeof window !== "undefined" ? window : global; } ctx = Object(ctx); const fnName = Symbol(); ctx[fnName] = this; const result = ctx[fnName](...args); delete ctx[fnName]; return result; }; ``` 用法: ```js let fn = function (name, sex) { console.log(this, name, sex); }; fn.apply("", ["前端胖头鱼", "boy"]); // { name: '前端胖头鱼', sex: 'boy', [Symbol()]: [Function: fn] } 前端胖头鱼 boy fn.apply({ name: "前端胖头鱼", sex: "boy" }, ["前端胖头鱼", "boy"]); ``` ## 数组去重 方法 1: set 法 ```js const uniqueArray = (array) => { return [...new Set(array)]; }; const uniqueArray = (array) => { return Array.from(new Set(array)); }; ``` 方法 2: indexOf 法: ```js const uniqueArray = (array) => { let result = []; array.forEach((it, i) => { if (result.indexOf(it) === -1) { result.push(it); } }); return result; }; const uniqueArray = (array) => { return array.filter((it, i) => array.indexOf(it) === i); }; ``` ## Promise ```js class Promise { constructor(exe) { this.value = undefined; this.status = "pending"; this.successQueue = []; this.failureQueue = []; const resolve = () => { const doResolve = (value) => { if (this.status === "pending") { this.status = "success"; this.value = value; while (this.successQueue.length) { const cb = this.successQueue.shift(); cb && cb(this.value); } } }; setTimeout(doResolve, 0); }; const reject = () => { const doReject = (value) => { if (this.status === "pending") { this.status = "failure"; this.value = value; while (this.failureQueue.length) { const cb = this.failureQueue.shift(); cb && cb(this.value); } } }; setTimeout(doReject, 0); }; exe(resolve, reject); } then(success = (value) => value, failure = (value) => value) { return new Promise((resolve, reject) => { const successFn = (value) => { try { const result = success(value); result instanceof Promise ? result.then(resolve, reject) : resolve(result); } catch (err) { reject(err); } }; const failureFn = (value) => { try { const result = failure(value); result instanceof Promise ? result.then(resolve, reject) : resolve(result); } catch (err) { reject(err); } }; if (this.status === "pending") { this.successQueue.push(successFn); this.failureQueue.push(failureFn); } else if (this.status === "success") { success(this.value); } else { failure(this.value); } }); } catch() {} } ``` 用法: ```js const pro = new Promise((resolve, reject) => { setTimeout(resolve, 1000); setTimeout(reject, 2000); }); pro .then(() => { console.log("2_1"); const newPro = new Promise((resolve, reject) => { console.log("2_2"); setTimeout(reject, 2000); }); console.log("2_3"); return newPro; }) .then( () => { console.log("2_4"); }, () => { console.log("2_5"); } ); pro .then( (data) => { console.log("3_1"); throw new Error(); }, (data) => { console.log("3_2"); } ) .then( () => { console.log("3_3"); }, (e) => { console.log("3_4"); } ); ``` ## Promise.all 方法 1: ```js Promise.all = (promises) => { return new Promise((rs, rj) => { let count = 0; let result = []; const len = promises.length; if (len === 0) { return resolve([]); } promises.forEach((p, i) => { Promise.resolve(p) .then((res) => { count += 1; result[i] = res; if (count === len) { rs(result); } }) .catch(rj); }); }); }; ``` 方法 2: ```js Promise.all = (promises) => { return new Promise((resolve, reject) => { if (!Array.isArray(promises)) { return reject("Promise.all accepts an array"); } const length = promises.length; let remaining = length; const result = []; if (length === 0) { return resolve([]); } const response = (i, value) => { try { if (value instanceof Promise) { // 注意此 val 非 value value.then((val) => { response(i, val); }, reject); return; } result[i] = value; if (--remaining === 0) { resolve(result); } } catch (err) { reject(err); } }; for (let i = 0; i < length; i++) { response(i, promises[i]); } }); }; ``` ## Promise.race ```js const noop = () => {}; Promise.race = (promises) => { return new Promise((rs = noop, rj = noop) => { promises.forEach((p) => { Promise.resolve(p).then(rs).catch(rj); }); }); }; ``` 用法: ```js const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 1); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 2); }); Promise.race([promise1, promise2]).then((value) => { console.log(value); // 2 }); Promise.race([promise1, promise2, 3]).then((value) => { console.log(value); // 3 }); ``` ## trim ```js String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ""); }; String.prototype.trim = function () { return this.replace(/^\s+(.*?)\s+$/, "$1"); }; ``` ## 手机号 344 分隔 ```js // 适合纯 11 位手机 const splitMobile = (mobile, format = "-") => { return String(mobile).replace(/(?=(\d{4})+$)/g, format); }; // 适合 11 位以内的分割 const splitMobile2 = (mobile, format = "-") => { return String(mobile) .replace(/(?<=(\d{3}))/, format) .replace(/(?<=([\d\-]{8}))/, format); }; ``` ## new ```js /** * new 的执行过程 * 1. 创建一个对象 obj * 2. 该对象的__proto__指向构造函数 Fn 的原型 prototype * 3. 执行构造函数 Fn 的代码,往新创建的对象 obj 上添加成员属性和方法 * 4. 返回这个新的对象 obj */ const _new = function (func, ...args) { if (typeof func !== "function") { throw "func must be a function"; } // 这里有点求快了,应该手动模拟一下 let obj = Object.create(func.prototype); // 实际模拟如下 /** let Ctor = function () {} Ctor.prototype = func.prototype Ctor.prototype.constructor = func let obj = new Ctor() */ let result = func.apply(obj, args); if ((typeof result === "object" && result !== null) || typeof result === "function") { return result; } else { return obj; } }; ``` 用法: ```js let Person = function (name, sex) { this.name = name; this.sex = sex; }; Person.prototype.showInfo = function () { console.log(this.name, this.sex); }; let p1 = _new(Person, "前端胖头鱼", "sex"); console.log(p1); // Person { name: '前端胖头鱼', sex: 'sex' } p1.showInfo(); // 前端胖头鱼 sex ``` ## deepClone ```js const deepClone = (target, cache = new Map()) => { if (isObject(target)) { const cacheObj = cache.get(target); if (cacheObj) return cacheObj; let cloneTarget = Array.isArray(target) ? [] : {}; cache.set(target, cloneTarget); Object.keys(target).forEach((key) => { const value = target[key]; cloneTarget[key] = isObject(value) ? deepClone2(value, cache) : value; }); return cloneTarget; } else { return target; } }; ``` 用法: ```js const target = { field1: 1, field2: undefined, field3: { child: "child", }, field4: [2, 4, 8], f: { f: { f: { f: { f: { f: { f: { f: { f: { f: { f: { f: {} } } } } } } } } } } }, }; target.target = target; console.time(); const result2 = deepClone(target); console.log(result2); console.timeEnd(); // default: 0.385ms ``` ## 金额转千分位 ```js const formatPrice = (number) => { const [integer, decimal = ""] = String(number).split("."); return integer.replace(/\B(?=(\d{3})+$)/g, ",") + (decimal ? "." + decimal : ""); }; ``` 用法: ``` console.log(formatPrice(123456789.3343)); // 123,456,789.3343 ``` ## Object.create ```js const create = (prop, props) => { if (!["object", "function"].includes(typeof prop)) { throw new TypeError(`Object prototype may only be an Object or null: ${prop}`); } const Ctor = function () {}; Ctor.prototype = prop; const obj = new Ctor(); if (props) { Object.defineProperties(obj, props); } // 支持空原型 if (prop === null) { obj.__proto__ = null; } return obj; }; ``` ## JSON.stringify ```js const stringify = (data) => { // 确认一个对象是否存在循环引用 const isCyclic = (obj) => { let stackSet = new Set(); let detected = false; const detect = (obj) => { if (obj && typeof obj != "object") { return; } if (stackSet.has(obj)) { return (detected = true); } stackSet.add(obj); for (let key in obj) { if (obj.hasOwnProperty(key)) { detect(obj[key]); } } stackSet.delete(obj); }; detect(obj); return detected; }; // 特性七: // 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。 if (isCyclic(data)) { throw new TypeError("Converting circular structure to JSON"); } // 特性九: // 当尝试去转换 BigInt 类型的值会抛出错误 if (typeof data === "bigint") { throw new TypeError("Do not know how to serialize a BigInt"); } const type = typeof data; const commonKeys1 = ["undefined", "function", "symbol"]; const getType = (s) => { return Object.prototype.toString .call(s) .replace(/\[object (.*?)\]/, "$1") .toLowerCase(); }; // 非对象 if (type !== "object" || data === null) { let result = data; // 特性四: // NaN 和 Infinity 格式的数值及 null 都会被当做 null。 if ([NaN, Infinity, null].includes(data)) { result = "null"; // 特性一: // `undefined`、` 任意的函数 ` 以及 `symbol 值 ` 被 ` 单独转换 ` 时,会返回 undefined } else if (commonKeys1.includes(type)) { // 直接得到 undefined,并不是一个字符串'undefined' return undefined; } else if (type === "string") { result = '"' + data + '"'; } return String(result); } else if (type === "object") { // 特性五: // 转换值如果有 toJSON() 方法,该方法定义什么值将被序列化 // 特性六: // Date 日期调用了 toJSON() 将其转换为了 string 字符串(同 Date.toISOString()),因此会被当做字符串处理。 if (typeof data.toJSON === "function") { return stringify(data.toJSON()); } else if (Array.isArray(data)) { let result = data.map((it) => { // 特性一: // `undefined`、` 任意的函数 ` 以及 `symbol 值 ` 出现在 ` 数组 ` 中时会被转换成 `null` return commonKeys1.includes(typeof it) ? "null" : stringify(it); }); return `[${result}]`.replace(/'/g, '"'); } else { // 特性二: // 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。 if (["boolean", "number"].includes(getType(data))) { return String(data); } else if (getType(data) === "string") { return '"' + data + '"'; } else { let result = []; // 特性八 // 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性 Object.keys(data).forEach((key) => { // 特性三: // 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。 if (typeof key !== "symbol") { const value = data[key]; // 特性一 // `undefined`、` 任意的函数 ` 以及 `symbol 值 `,出现在 ` 非数组对象 ` 的属性值中时在序列化过程中会被忽略 if (!commonKeys1.includes(typeof value)) { result.push(`"${key}":${stringify(value)}`); } } }); return `{${result}}`.replace(/'/, '"'); } } } }; ``` 用法: ```js console.log(stringify(undefined)); // undefined console.log(stringify(() => {})); // undefined console.log(stringify(Symbol("前端胖头鱼"))); // undefined console.log(stringify(NaN)); // null console.log(stringify(Infinity)); // null console.log(stringify(null)); // null console.log( stringify({ name: "前端胖头鱼", toJSON() { return { name: "前端胖头鱼 2", sex: "boy", }; }, }) ); ``` ## once 创建一个只能调用 `func` 一次的函数。 重复调用返回第一次调用的结果。 `func` 调用时, `this` 绑定到创建的函数,并传入对应参数。 ```js // see https://www.lodashjs.com/docs/lodash.once function once(func) { return before(2, func); } const FUNC_ERROR_TEXT = 'Expected a function'; function before(n, func) { let result; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } n = toInteger(n); return function () { if (--n > 0) { result = func.apply(this, arguments); } if (n <= 1) { func = undefined; } return result; }; } ```
追风者
2022年4月21日 10:25
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码