场景题汇总一 类数组转化为数组 通过 call 调用数组的 slice 方法来实现转换 1 Array .prototype.slice.call(arrayLike);
通过 call 调用数组的 splice 方法来实现转换 1 Array .prototype.splice.call(arrayLike, 0 );
通过 apply 调用数组的 concat 方法来实现转换 1 Array .prototype.concat.apply([], arrayLike);
通过 Array.from 方法来实现转换
将js对象转化为树形结构 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 source = [{ id : 1 , pid : 0 , name : 'body' }, { id : 2 , pid : 1 , name : 'title' }, { id : 3 , pid : 2 , name : 'div' }] tree = [{ id : 1 , pid : 0 , name : 'body' , children : [{ id : 2 , pid : 1 , name : 'title' , children : [{ id : 3 , pid : 1 , name : 'div' }] } }]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function jsonToTree (data ) { let result = [] if (!Array .isArray(data)) { return result } let map = {}; data.forEach(item => { map[item.id] = item; }); data.forEach(item => { let parent = map[item.pid]; if (parent) { (parent.children || (parent.children = [])).push(item); } else { result.push(item); } }); return result; }
小孩报数问题 有30个小孩儿,编号从1-30,围成一圈依此报数,1、2、3 数到 3 的小孩儿退出这个圈, 然后下一个小孩 重新报数 1、2、3,问最后剩下的那个小孩儿的编号是多少?
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 function childNum (num, count ) { let allplayer = []; for (let i = 0 ; i < num; i++){ allplayer[i] = i + 1 ; } let exitCount = 0 ; let counter = 0 ; let curIndex = 0 ; while (exitCount < num - 1 ){ if (allplayer[curIndex] !== 0 ) counter++; if (counter == count){ allplayer[curIndex] = 0 ; counter = 0 ; exitCount++; } curIndex++; if (curIndex == num){ curIndex = 0 }; } for (i = 0 ; i < num; i++){ if (allplayer[i] !== 0 ){ return allplayer[i] } } } childNum(30 , 3 )
用Promise实现图片的异步加载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let imageAsync=(url )=> { return new Promise ((resolve,reject )=> { let img = new Image(); img.src = url; img.οnlοad=()=> { console .log(`图片请求成功,此处进行通用操作` ); resolve(image); } img.οnerrοr=(err )=> { console .log(`失败,此处进行失败的通用操作` ); reject(err); } }) } imageAsync("url" ).then(()=> { console .log("加载成功" ); }).catch((error )=> { console .log("加载失败" ); })
实现发布-订阅模式 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 class EventCenter { let handlers = {} addEventListener (type, handler ) { if (!this .handlers[type]) { this .handlers[type] = [] } this .handlers[type].push(handler) } dispatchEvent (type, params ) { if (!this .handlers[type]) { return new Error ('该事件未注册' ) } this .handlers[type].forEach(handler => { handler(...params) }) } removeEventListener (type, handler ) { if (!this .handlers[type]) { return new Error ('事件无效' ) } if (!handler) { delete this .handlers[type] } else { const index = this .handlers[type].findIndex(el => el === handler) if (index === -1 ) { return new Error ('无该绑定事件' ) } this .handlers[type].splice(index, 1 ) if (this .handlers[type].length === 0 ) { delete this .handlers[type] } } } }
查找文章中出现频率最高的单词 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 function findMostWord (article ) { if (!article) return ; article = article.trim().toLowerCase(); let wordList = article.match(/[a-z]+/g ), visited = [], maxNum = 0 , maxWord = "" ; article = " " + wordList.join(" " ) + " " ; wordList.forEach(function (item ) { if (visited.indexOf(item) < 0 ) { visited.push(item); let word = new RegExp (" " + item + " " , "g" ), num = article.match(word).length; if (num > maxNum) { maxNum = num; maxWord = item; } } }); return maxWord + " " + maxNum; }
封装异步的fetch,使用async await方式来使用 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 (async () => { class HttpRequestUtil { async get (url ) { const res = await fetch(url); const data = await res.json(); return data; } async post (url, data ) { const res = await fetch(url, { method : 'POST' , headers : { 'Content-Type' : 'application/json' }, body : JSON .stringify(data) }); const result = await res.json(); return result; } async put (url, data ) { const res = await fetch(url, { method : 'PUT' , headers : { 'Content-Type' : 'application/json' }, data : JSON .stringify(data) }); const result = await res.json(); return result; } async delete (url, data ) { const res = await fetch(url, { method : 'DELETE' , headers : { 'Content-Type' : 'application/json' }, data : JSON .stringify(data) }); const result = await res.json(); return result; } } const httpRequestUtil = new HttpRequestUtil(); const res = await httpRequestUtil.get('http://golderbrother.cn/' ); console .log(res); })();
实现prototype继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function SupperFunction (flag1 ) { this .flag1 = flag1; } function SubFunction (flag2 ) { this .flag2 = flag2; } var superInstance = new SupperFunction(true );SubFunction.prototype = superInstance; var subInstance = new SubFunction(false );subInstance.flag1; subInstance.flag2;
实现双向数据绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let obj = {}let input = document .getElementById('input' )let span = document .getElementById('span' )Object .defineProperty(obj, 'text' , { configurable : true , enumerable : true , get ( ) { console .log('获取数据了' ) }, set (newVal ) { console .log('数据更新了' ) input.value = newVal span.innerHTML = newVal } }) input.addEventListener('keyup' , function (e ) { obj.text = e.target.value })
实现简单路由 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Route { constructor ( ) { this .routes = {} this .currentHash = '' this .freshRoute = this .freshRoute.bind(this ) window .addEventListener('load' , this .freshRoute, false ) window .addEventListener('hashchange' , this .freshRoute, false ) } storeRoute (path, cb) { this .routes[path] = cb || function ( ) {} } freshRoute () { this .currentHash = location.hash.slice(1 ) || '/' this .routes[this .currentHash]() } }
实现斐波那契数列 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 function fn (n ) { if (n==0 ) return 0 if (n==1 ) return 1 return fn(n-2 )+fn(n-1 ) } function fibonacci2 (n ) { const arr = [1 , 1 , 2 ]; const arrLen = arr.length; if (n <= arrLen) { return arr[n]; } for (let i = arrLen; i < n; i++) { arr.push(arr[i - 1 ] + arr[ i - 2 ]); } return arr[arr.length - 1 ]; } function fn (n ) { let pre1 = 1 ; let pre2 = 1 ; let current = 2 ; if (n <= 2 ) { return current; } for (let i = 2 ; i < n; i++) { pre1 = pre2; pre2 = current; current = pre1 + pre2; } return current; }
字符串出现的不重复最长长度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var lengthOfLongestSubstring = function (s ) { let map = new Map (); let i = -1 let res = 0 let n = s.length for (let j = 0 ; j < n; j++) { if (map.has(s[j])) { i = Math .max(i, map.get(s[j])) } res = Math .max(res, j - i) map.set(s[j], j) } return res };
使用 setTimeout 实现 setInterval
setInterval 的作用是每隔一段指定时间执行一个函数,但是这个执行不是真的到了时间立即执行,它真正的作用是每隔一段时间将事件加入事件队列中去,只有当当前的执行栈为空的时候,才能去从事件队列中取出事件执行。所以可能会出现这样的情况,就是当前执行栈执行的时间很长,导致事件队列里边积累多个定时器加入的事件,当执行栈结束的时候,这些事件会依次执行,因此就不能到间隔一段时间执行的效果。 针对 setInterval 的这个缺点,我们可以使用 setTimeout 递归调用来模拟 setInterval,这样我们就确保了只有一个事件结束了,我们才会触发下一个定时器事件,这样解决了 setInterval 的问题。 实现思路是使用递归函数,不断地去执行 setTimeout 从而达到 setInterval 的效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function mySetInterval (fn, timeout ) { var timer = { flag : true }; function interval ( ) { if (timer.flag) { fn(); setTimeout (interval, timeout); } } setTimeout (interval, timeout); return timer; }
实现 jsonp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function addScript (src ) { const script = document .createElement('script' ); script.src = src; script.type = "text/javascript" ; document .body.appendChild(script); } addScript("http://xxx.xxx.com/xxx.js?callback=handleRes" ); function handleRes (res ) { console .log(res); } handleRes({a : 1 , b : 2 });
判断对象是否存在循环引用 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 const isCycleObject = (obj,parent ) => { const parentArr = parent || [obj]; for (let i in obj) { if (typeof obj[i] === 'object' ) { let flag = false ; parentArr.forEach((pObj ) => { if (pObj === obj[i]){ flag = true ; } }) if (flag) return true ; flag = isCycleObject(obj[i],[...parentArr,obj[i]]); if (flag) return true ; } } return false ; } const a = 1 ;const b = {a};const c = {b};const o = {d :{a :3 },c}o.c.b.aa = a; console .log(isCycleObject(o)