手撕代码系列(二)
手写函数柯里化 curring
/** * 函数柯里化 curring * @param {Function} * @return 视具体方法而定 * * @logic * 1.创建一个参数数组 args * 2.创建一个函数,接收参数列表 * 3.函数判断参数数组是否有值 * 4.如果有值,则往 args 中进行 push 操作,否则就是没有参数了,则直接进行调用 * 5.调用后,将 args 参数数组清空 * 6.返回参数数组 */ const curring = fn => { let args = []; return function temp(...rest) { if (rest.length) { args.push(...rest); return temp; } else { let result = fn.apply(this, args); args = []; return result; } } } // test: const add = (...args) => { return args.reduce((prev, next) => prev + next, 0); } console.log(curring(add)(1)(2)(3)(4)(5)()); // 15 console.log(curring(add)(1)(2)(3)(4,5)()); // 15 console.log(curring(add)(1,2)(3,4,5)()); // 15 console.log(curring(add)(1)(2,3,4,5)()); // 15
手写数组乱序方法 shuffle
/** * 随机洗牌 * @param {Array} arr 要被打乱的数组 * @returns 打乱后的元素 * * @logic * 1. 从还没处理的数组中,从 [0, array.length] 之间取一个随机数 random number * 2. 从剩下的 array.length 中把第 random 元素取出来放在新数组 result 中 * 3. 删除原数组中第 random 个元素 * 4. 重复2,3步骤直到所有元素取完 * 5. 最终返回新数组即可 */ const shuffle = source => { let arr = Array.from(source); let result = []; while (arr.length) { let random = (Math.random() * arr.length) | 0; // let random = Math.floor(Math.random() * arr.length); // let random = (Math.random() * arr.length) >> 0; // let random = (Math.random() * arr.length) << 0; // let random = (Math.random() * arr.length) >>> 0; // let random = ~~(Math.random() * arr.length); result.push(arr[random]); arr.splice(random, 1) } return result; } // test: let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; console.log("shuffle(numbers) ------->", shuffle(numbers)); // shuffle(numbers) -------> [ // 9, 1, 17, 6, 10, 12, 18, // 19, 20, 8, 13, 2, 11, 15, // 7, 4, 16, 14, 5, 3 // ]
手写解析 URL Params 方法 getUrlParams
/** * 解析 URL Params getUrlParams * @param {String} urlStr * @return {Object} 参数对象 */ // 方法一: const getUrlParams = url => { // 解析url,获取参数部分 let urlStr = url.split('?')[1]; // 判断是否有 hash 值 let newStr = ''; // 去重 hash 值逻辑 if (urlStr.includes('#')) { newStr = urlStr.split('#')[0]; } // 参数重置化 let res = new URLSearchParams(newStr); // Object.fromEntries() 方法将 key value 数组形式转换为对象; /** demo: let obj = { a: 1, b: 2 } console.log(Object.fromEntries(Object.entries(obj))); */ return Object.fromEntries(res.entries()) } // 方法二: const getUrlParams = url => { let urlParams = new URL(url); return Object.fromEntries(urlParams.searchParams.entries()); } // test: let tempUrl = "https://www.baidu.com:80/temp/src/index.html?name=John&sex=14#hash=title"; console.log("getUrlParams(tempUrl) ------->", getUrlParams(tempUrl)); // getUrlParams(tempUrl) -------> { name: 'John', sex: '14' }
手写数组扁平化 myFlat
/** * 数组扁平化 myFlat * @param {Array} source 需要扁平化的数组 * @returns 扁平化后的新数组 */ // 方法一: const myFlat = source => { // 结果数组 let result = []; // 遍历 for (let i = 0; i < source.length; i++){ // 数组元素 let item = source[i]; // 判断当前项是否为数组,若是数组递归执行 if (Array.isArray(item)) { // result.concat(myFlat(item)) 使用之前的列表(result)拼接当前的列表(item),因为 concat 不会修改原数组,重新赋值给 result 数组 result = result.concat(myFlat(item)); } else { // 不是数组,则添加到 result 数组中 result.push(item); } } // 返回结果 return result; } // 方法二: // some + 扩展运算符:通过 while 循环来持续判断当前项是否为数组,如果为数组,直接修改原数组 arr 等于 空数组展开当前数组,按此逻辑继续执行。 // some:如果有一个满足条件,则返回 true, 后续将和 includes 和 indexof 方法一样,不会再进行后续检测,如果不满足则返回 false // any: 数组中的所有元素都满足条件,返回 boolean 值。 const MyFlat = (arr) => { while (arr.some((item) => Array.isArray(item))) { console.log(arr); arr = [].concat(...arr); } return arr; }; // 方法三: // split + toString(): 此方法弊端,如果数组中的元素都是数字,那经过此方法会直接转为字符串。 const MyFlat = (arr) => { return arr.toString().split(","); }; // 方法四: // ES6 flat const MyFlat = (arr) => { return arr.flat(Infinity); }; // test: let arr = [1, [2, [3, 4, 5]]]; console.log("myFlat(arr) after------>", myFlat(arr)); // myFlat(arr) after------> [ 1, 2, 3, 4, 5 ]
手写 myInstanceof
/** * instanceof * instanceof 运算符用户检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。 * 语法:object(实例对象) instanceof constructor(构造函数,与 prototype 是成对出现的,你指向我,我指向你) * @param {Object} object 某个实例对象 * @param {Function} constructorFn 某个构造函数 * @return {Boolean} */ const myInstanceof = (object, constructorFn) => { // Object.getPrototypeOf(object) === object.__proto__; 都是用来获取某个对象的隐式原型 let objectRes = Object.getPrototypeOf(object); // prototype:显式原型 const constructorRes = constructorFn.prototype; while (true) { if (!objectRes) return false; // 如果构造函数的 prototype 在对象的实例中,直接返回 true if (objectRes === constructorRes) return true; // 继续向下寻找 objectRes = Object.getPrototypeOf(objectRes); } }; // test: function F() { }; function D() { }; let f = new F(); // 表示: 构造函数 F 是否出现在 f 对象实例上 console.log(myInstanceof(f, F)); // true // 表示: 构造函数 D 是否出现在 f 对象实例上 console.log(myInstanceof(f, D)); // false
特殊字符描述
•问题标注 Q:(question)
•答案标注 R:(result)
•注意事项标准:A:(attention matters)
•详情描述标注:D:(detail info)
•总结标注:S:(summary)
•分析标注:Ana:(analysis)
•提示标注:T:(tips)