1、防抖和节流函数 防抖的主要思想是,当事件被触发后,延迟一定时间再执行相关操作。如果在这个延迟期内再次触发了同样的事件,就会重新计时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const debounce = function (fn, delay ) { let timer = null ; return function ( ) { const that = this ; if (timer){ clearTimeout(timer); timer = null ; } timer = setTimeout(function ( ) { fn.apply(that, arguments ); }, delay) } } window .addEventListener('resize' , debounce(() => { console .log('防抖执行' ); }, 300 ));
节流的主要思想是,在一定时间内只允许函数执行一次,无论事件触发了多少次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const throttle = function (fn, delay ) { let lastTime = 0 ; return function ( ) { const now = Date .now(); if (now - lastTime > delay){ fn.apply(this , arguments ); lastTime = now; } } } window .addEventListener('scroll' , throttle(() => { console .log('节流执行' ); }, 300 ));
2、实现apply方法 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 Function .prototype.myApply = function (thisArg, argsArray ) { if (typeof this !== 'function' ){ throw new TypeError ('myApply muse be called on a function' ); } thisArg = (thisArg == null ? globalThis : Object (thisArg)); const fnKey = Symbol ('fn' ); thisArg[fnKey] = this ; const result = argsArray ? thisArg[fnKey](...argsArray) : thisArg[fnKey](); delete thisArg[fnKey]; return result; } function greet (m1, m2 ) { return `${m1} , ${this .name} , ${m2} ` ; } const person = { name: 'frank' } greet.myApply(person, ['hello' , 'come on' ]);
3、实现call方法 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 Function .prototype.myCall = function (thisArg, ...arg ) { if (typeof this !== 'function' ){ throw new TypeError ('myCall must be called on a function' ); } thisArg = (thisArg == null ? globalThis : Object (thisArg)) const fnKey = Symbol ('fn' ); thisArg[fnKey] = this ; const result = thisArg[fnKey](...arg); delete thisArg[fnKey]; return result; } function greet (m1, m2 ) { return `${m1} , ${this .name} , ${m2} ` ; } const person = { name: 'frank' } greet.myCall(person, 'hello' , 'come on' );
4、实现bind方法 bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const obj = { name: 'zc' , age: 12 } function say (sex ) { console .log(`name: ${this .name} , age: ${this .age} , sex: ${sex} , 参数: ${[...arguments ]} ` ); } const mySay = say.bind(obj, 'female' );mySay(111 ); Function .prototype.myBind = function (context ) { const that = this ; const args = Array .prototype.slice.call(arguments , 1 ); return function ( ) { const newArgs = Array .prototype.slice.call(arguments ); return that.apply(context, [...args, ...newArgs]); } } const mySay1 = say.myBind(obj, 'female' );mySay1(222 );
5、统计字符串出现最多的字符 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 let str = 'afjghdfraaaasdenas' ;function findMaxDuplicateChar (str ) { if (str.length === 1 ) return str; let charObj = {}; for (let i=0 ; i<str.length; i++) { if (!charObj[str.charAt(i)]){ charObj[str.charAt(i)] = 1 ; } else { charObj[str.charAt(i)] += 1 ; } } let maxChar = '' , maxValue = 1 ; for (let key in charObj) { if (charObj[key] >= maxChar) { maxChar = key; maxValue = charObj[key]; } } return { maxChar, maxValue } }
6、统计字符串中第一个唯一字符 1 2 3 4 5 6 7 8 9 10 11 12 let str = 'leetcode' ; function findFirstUniqChar (str ) { for (let i=0 ; i<str.length(); i++) { let curChar = str[i]; if (str.lastIndexOf(curChar) === str.indexOf(curChar)) { return i; } } return -1 ; }
7、找出数组中出现次数最多的元素,并给出其出现过的位置 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 let arr = [1 , 2 , 1 , 1 , 4 , 5 , 6 ];function findMostItemByArr (arr ) { let mostItem, indexs = [], obj = {}; for (let i=0 ; i<arr.length; i++) { let item = arr[i].toString(); obj[item] ? obj[item].push(i) : obj[item] = [].concat(i); } let tempArr = Object .entries(obj); mostItem = parseInt (tempArr[0 ][0 ]); indexs = tempArr[0 ][1 ]; for (const [key, value] of tempArr) { if (indexs.length < value.length) { mostItem = parseInt (key); indexs = value; } } return { mostItem, indexs, } }
8、数组扁平化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function flatten (arr ) { const result = []; for (let i = 0 ; i < arr.length; i++) { if (Array .isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result = result.concat(arr[i]); } } return result; } if (!Array .prototype.flat) { Array .prototype.flat = function ( ) { return [].concat(...this.map(item => Array .isArray(item) ? item.flat() : [item])); } }
9、讲数组扁平化并去除其中重复数据, 最终得到一个升序且不重复的数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let arr = [ [1 , 2 , 2 ], [3 , 4 , 5 , 5 ], [6 , 7 , 8 , 9 , [11 , 12 , [12 , 13 , [14 ] ] ] ], 10 ];Array .prototype.flat = function ( ) { return [].concat(...this.map(item => Array .isArray(item) ? item.flat() : [item])); } Array .prototype.unique = function ( ) { return [...new Set (this )]; } arr.flat().unique().sort((a, b ) => a -b);
10、旋转数组 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
1 2 3 4 5 6 7 8 9 let arr = [1 , 2 , 3 , 4 , 5 , 6 , 7 ];function rotate (arr, k ) { for (let i=0 ; i<k; i++) { let temp = arr.pop(); arr.unshift(); } return arr; }
11、版本比较 根据两个版本号,当前版本v1和比较版本v2,判断app是否为旧版本。
示例1:v1=”1.01”, v2=”1.1”, 则为旧版本
示例2:v1=”2.5”,v2=”2.4”, 则为新版本
示例3: v1=”5.4.3.2”, v2=”5.4.3”, 则为新版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var compareVersion = function (version1, version2 ) { if (!version1 || !version2) return 0 const v1 = String (version1).split('.' ); const v2 = String (version2).split('.' ); const maxLen = Math .max(v1.length, v2.length); for (let i = 0 ; i < maxLen; i++){ const num1 = Number (v1[i]) || 0 ; const num2 = Number (v2[i]) || 0 ; if (num1 > num2) return 1 ; if (num1 < num2) return -1 ; } return 0 ; };
11、数据转化为树状结构 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 let arr = [ { id : 1 , name : '1' , pid : 0 , }, { id : 2 , name : '1-1' , pid : 1 , }, { id : 3 , name : '1-1-1' , pid : 2 , }, { id : 4 , name : '1-2' , pid : 1 , } ]; function json2Tree (data, parentId = 0 ) { return data .filter(item => item.pid === parentId) .map(item => { const children = json2Tree(data, item.id); return { ...item, children: children.length ? children : undefined }; }); } console .log(JSON .stringify(json2Tree(arr), null , 2 ));[ { "id" : 1 , "name" : "1" , "pid" : 0 , "children" : [ { "id" : 2 , "name" : "1-1" , "pid" : 1 , "children" : [ { "id" : 3 , "name" : "1-1-1" , "pid" : 2 } ] }, { "id" : 4 , "name" : "1-2" , "pid" : 1 } ] } ]
12、找出字符串中所有字母的所有可能的排列,假定字母不重复 例如:”abc” 可能的排列为:”abc”, “acb”, “bac”, “bca”, “cab”, “cba”
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 function allPermutationsBacktrack (str ) { const res = []; const chars = str.split('' ); const used = new Array (chars.length).fill(false ); function backtrack (path ) { if (path.length === chars.length){ res.push(path.join('' )); return ; } for (let i = 0 ; i < chars.length; i++){ if (used[i]) continue ; used[i] = true ; path.push(chars[i]); backtrack(path); path.pop(); used[i] = false ; } } backtrack([]); return res; } console .log(allPermutationsBacktrack('abc' ));
13、实现字符串模板 1 2 3 4 5 6 7 8 9 10 function tpl (template, data ) { }tpl('<div class={{className}}>{{name}}</div>' , { className: 'class1' , name: 'test' }); <div class ="class" >test</div>
1 2 3 4 5 function tpl (str, data ) { return str.replace(/{{\s*(\w+)\s*}}/g , (match, key) => { return key in data ? data[key] : '' ; }); }
14、实现字符串大数相加 大数相加指的是两个超出编程语言内置数值精度范围的整数相加,通常用字符串(或数组)来存储并模拟计算的过程。
1 2 3 4 Number .MAX_SAFE_INTEGER console .log(9007199254740991 + 1 ); console .log(9007199254740991 + 2 );
实现思路
反转字符串(或从末位开始遍历),方便低位到高位逐位相加。
用 carry 保存进位。
把对应位数字相加,计算新的一位和新的进位。
最后如果 carry > 0,别忘了加到结果最高位。
反转结果字符串得到最终值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function plus (num1, num2 ) { let i = num1.length - 1 ; let j = num2.length - 1 ; let carry = 0 ; let res = []; while (i >= 0 || j >= 0 || carry) { const n1 = i >= 0 ? parseInt (num1[i], 10 ) : 0 ; const n2 = j >= 0 ? parseInt (num2[j], 10 ) : 0 ; const sum = n1 + n2 + carry; res.push(sum % 10 ); carry = Math .floor(sum / 10 ); i--; j--; } return res.reverse().join('' ); } console .log(plus("123456789123456789" , "987654321987654321" ));
15、实现安全取值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function getValSafe (obj, keys ) {} const obj = { a : { b : { c : { d : 'safe' } } } }console .log(get (obj, 'a.b.c.d')); //=> 'safe'//方法一: ?. 链式写法 //方法二 function getValSafe(obj, keys) { let result = obj; keys.split('.' ).forEach(key => { if (result && result[key]) { result = result[key]; } else { result = undefined ; } }); return result; } function getValSafe (obj, keys ) { return keys.reduce((acc, key ) => (acc && acc[key] !== undefined ? acc[key] : undefined ), obj); }