自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

32個(gè)手撕JS,徹底擺脫初級(jí)前端(面試高頻)-上篇

開發(fā)
作為前端開發(fā),JS是重中之重,最近結(jié)束了面試的高峰期,基本上offer也定下來了就等開獎(jiǎng),趁著這個(gè)時(shí)間總結(jié)下32個(gè)手撕JS問題,這些都是高頻面試題,完全理解之后定能徹底擺脫初級(jí)前端。

[[344056]]

 關(guān)于源碼都緊遵規(guī)范,都可跑通MDN示例,其余的大多會(huì)涉及一些關(guān)于JS的應(yīng)用題和本人面試過程

01.數(shù)組扁平化
數(shù)組扁平化是指將一個(gè)多維數(shù)組變?yōu)橐粋€(gè)一維數(shù)組

  1. const arr = [1, [2, [3, [4, 5]]], 6]; 
  2. // => [1, 2, 3, 4, 5, 6] 
  3. 復(fù)制代碼 

方法一:使用flat()

  1. const res1 = arr.flat(Infinity); 
  2. 復(fù)制代碼 

方法二:利用正則

  1. const res2 = JSON.stringify(arr).replace(/\[|\]/g, '').split(','); 
  2. 復(fù)制代碼 

但數(shù)據(jù)類型都會(huì)變?yōu)樽址?/p>

方法三:正則改良版本

  1. const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g, '') + ']'); 
  2. 復(fù)制代碼 

方法四:使用reduce

  1. const flatten = arr => { 
  2.   return arr.reduce((pre, cur) => { 
  3.     return pre.concat(Array.isArray(cur) ? flatten(cur) : cur); 
  4.   }, []) 
  5. const res4 = flatten(arr); 
  6. 復(fù)制代碼 

方法五:函數(shù)遞歸

  1. const res5 = []; 
  2. const fn = arr => { 
  3.   for (let i = 0; i < arr.length; i++) { 
  4.     if (Array.isArray(arr[i])) { 
  5.       fn(arr[i]); 
  6.     } else { 
  7.       res5.push(arr[i]); 
  8.     } 
  9.   } 
  10. fn(arr); 
  11. 復(fù)制代碼 

02.數(shù)組去重

  1. const arr = [1, 1, '1', 17, truetruefalsefalse'true''a', {}, {}]; 
  2. // => [1, '1', 17, truefalse'true''a', {}, {}] 
  3. 復(fù)制代碼 

方法一:利用Set

  1. const res1 = Array.from(new Set(arr)); 
  2. 復(fù)制代碼 

方法二:兩層for循環(huán)+splice

  1. const unique1 = arr => { 
  2.   let len = arr.length; 
  3.   for (let i = 0; i < len; i++) { 
  4.     for (let j = i + 1; j < len; j++) { 
  5.       if (arr[i] === arr[j]) { 
  6.         arr.splice(j, 1); 
  7.         // 每刪除一個(gè)樹,j--保證j的值經(jīng)過自加后不變。同時(shí),len--,減少循環(huán)次數(shù)提升性能 
  8.         len--; 
  9.         j--; 
  10.       } 
  11.     } 
  12.   } 
  13.   return arr; 
  14. 復(fù)制代碼 

方法三:利用indexOf

  1. const unique2 = arr => { 
  2.   const res = []; 
  3.   for (let i = 0; i < arr.length; i++) { 
  4.     if (res.indexOf(arr[i]) === -1) res.push(arr[i]); 
  5.   } 
  6.   return res; 
  7. 復(fù)制代碼 

當(dāng)然也可以用include、filter,思路大同小異。

方法四:利用include

  1. const unique3 = arr => { 
  2.   const res = []; 
  3.   for (let i = 0; i < arr.length; i++) { 
  4.     if (!res.includes(arr[i])) res.push(arr[i]); 
  5.   } 
  6.   return res; 
  7. 復(fù)制代碼 

方法五:利用filter

  1. const unique4 = arr => { 
  2.   return arr.filter((item, index) => { 
  3.     return arr.indexOf(item) === index
  4.   }); 
  5. 復(fù)制代碼 

方法六:利用Map

  1. const unique5 = arr => { 
  2.   const map = new Map(); 
  3.   const res = []; 
  4.   for (let i = 0; i < arr.length; i++) { 
  5.     if (!map.has(arr[i])) { 
  6.       map.set(arr[i], true
  7.       res.push(arr[i]); 
  8.     } 
  9.   } 
  10.   return res; 
  11. 復(fù)制代碼 

03.類數(shù)組轉(zhuǎn)化為數(shù)組
類數(shù)組是具有l(wèi)ength屬性,但不具有數(shù)組原型上的方法。常見的類數(shù)組有arguments、DOM操作方法返回的結(jié)果。

方法一:Array.from

  1. Array.from(document.querySelectorAll('div')) 
  2. 復(fù)制代碼 

方法二:Array.prototype.slice.call()

  1. Array.prototype.slice.call(document.querySelectorAll('div')) 
  2. 復(fù)制代碼 

方法三:擴(kuò)展運(yùn)算符

  1. [...document.querySelectorAll('div')] 
  2. 復(fù)制代碼 

方法四:利用concat

  1. Array.prototype.concat.apply([], document.querySelectorAll('div')); 
  2. 復(fù)制代碼 

04.Array.prototype.filter()

  1. rray.prototype.filter = function(callback, thisArg) { 
  2.   if (this == undefined) { 
  3.     throw new TypeError('this is null or not undefined'); 
  4.   } 
  5.   if (typeof callback !== 'function') { 
  6.     throw new TypeError(callback + 'is not a function'); 
  7.   } 
  8.   const res = []; 
  9.   // 讓O成為回調(diào)函數(shù)的對(duì)象傳遞(強(qiáng)制轉(zhuǎn)換對(duì)象) 
  10.   const O = Object(this); 
  11.   // >>>0 保證len為number,且為正整數(shù) 
  12.   const len = O.length >>> 0; 
  13.   for (let i = 0; i < len; i++) { 
  14.     // 檢查i是否在O的屬性(會(huì)檢查原型鏈) 
  15.     if (i in O) { 
  16.       // 回調(diào)函數(shù)調(diào)用傳參 
  17.       if (callback.call(thisArg, O[i], i, O)) { 
  18.         res.push(O[i]); 
  19.       } 
  20.     } 
  21.   } 
  22.   return res; 
  23. 復(fù)制代碼 

對(duì)于>>>0有疑問的:解釋>>>0的作用

05.Array.prototype.map()

  1. Array.prototype.map = function(callback, thisArg) { 
  2.   if (this == undefined) { 
  3.     throw new TypeError('this is null or not defined'); 
  4.   } 
  5.   if (typeof callback !== 'function') { 
  6.     throw new TypeError(callback + ' is not a function'); 
  7.   } 
  8.   const res = []; 
  9.   // 同理 
  10.   const O = Object(this); 
  11.   const len = O.length >>> 0; 
  12.   for (let i = 0; i < len; i++) { 
  13.     if (i in O) { 
  14.       // 調(diào)用回調(diào)函數(shù)并傳入新數(shù)組 
  15.       res[i] = callback.call(thisArg, O[i], i, this); 
  16.     } 
  17.   } 
  18.   return res; 
  19. 復(fù)制代碼 

06.Array.prototype.forEach()

forEach跟map類似,唯一不同的是forEach是沒有返回值的。

  1. Array.prototype.forEach = function(callback, thisArg) { 
  2.   if (this == null) { 
  3.     throw new TypeError('this is null or not defined'); 
  4.   } 
  5.   if (typeof callback !== "function") { 
  6.     throw new TypeError(callback + ' is not a function'); 
  7.   } 
  8.   const O = Object(this); 
  9.   const len = O.length >>> 0; 
  10.   let k = 0; 
  11.   while (k < len) { 
  12.     if (k in O) { 
  13.       callback.call(thisArg, O[k], k, O); 
  14.     } 
  15.     k++; 
  16.   } 
  17. 復(fù)制代碼 

07.Array.prototype.reduce()

  1. Array.prototype.reduce = function(callback, initialValue) { 
  2.   if (this == undefined) { 
  3.     throw new TypeError('this is null or not defined'); 
  4.   } 
  5.   if (typeof callback !== 'function') { 
  6.     throw new TypeError(callbackfn + ' is not a function'); 
  7.   } 
  8.   const O = Object(this); 
  9.   const len = this.length >>> 0; 
  10.   let accumulator = initialValue; 
  11.   let k = 0; 
  12.   // 如果第二個(gè)參數(shù)為undefined的情況下 
  13.   // 則數(shù)組的第一個(gè)有效值作為累加器的初始值 
  14.   if (accumulator === undefined) { 
  15.     while (k < len && !(k in O)) { 
  16.       k++; 
  17.     } 
  18.     // 如果超出數(shù)組界限還沒有找到累加器的初始值,則TypeError 
  19.     if (k >= len) { 
  20.       throw new TypeError('Reduce of empty array with no initial value'); 
  21.     } 
  22.     accumulator = O[k++]; 
  23.   } 
  24.   while (k < len) { 
  25.     if (k in O) { 
  26.       accumulator = callback.call(undefined, accumulator, O[k], k, O); 
  27.     } 
  28.     k++; 
  29.   } 
  30.   return accumulator; 
  31. 復(fù)制代碼 

08.Function.prototype.apply()
第一個(gè)參數(shù)是綁定的this,默認(rèn)為window,第二個(gè)參數(shù)是數(shù)組或類數(shù)組

  1. Function.prototype.apply = function(context = window, args) { 
  2.   if (typeof this !== 'function') { 
  3.     throw new TypeError('Type Error'); 
  4.   } 
  5.   const fn = Symbol('fn'); 
  6.   context[fn] = this; 
  7.  
  8.   const res = context[fn](...args); 
  9.   delete context[fn]; 
  10.   return res; 
  11. 復(fù)制代碼 

09.Function.prototype.call
于call唯一不同的是,call()方法接受的是一個(gè)參數(shù)列表

  1. Function.prototype.call = function(context = window, ...args) { 
  2.   if (typeof this !== 'function') { 
  3.     throw new TypeError('Type Error'); 
  4.   } 
  5.   const fn = Symbol('fn'); 
  6.   context[fn] = this; 
  7.  
  8.   const res = this[fn](...args); 
  9.   delete this.fn; 
  10.   return res; 
  11. 復(fù)制代碼 

10.Function.prototype.bind

  1. Function.prototype.bind = function(context, ...args) { 
  2.   if (typeof this !== 'function') { 
  3.     throw new Error("Type Error"); 
  4.   } 
  5.   // 保存this的值 
  6.   var self = this; 
  7.  
  8.   return function F() { 
  9.     // 考慮new的情況 
  10.     if(this instanceof F) { 
  11.       return new self(...args, ...arguments) 
  12.     } 
  13.     return self.apply(context, [...args, ...arguments]) 
  14.   } 
  15. 復(fù)制代碼 

11.debounce(防抖)
觸發(fā)高頻時(shí)間后n秒內(nèi)函數(shù)只會(huì)執(zhí)行一次,如果n秒內(nèi)高頻時(shí)間再次觸發(fā),則重新計(jì)算時(shí)間。

  1. const debounce = (fn, time) => { 
  2.   let timeout = null
  3.   return function() { 
  4.     clearTimeout(timeout) 
  5.     timeout = setTimeout(() => { 
  6.       fn.apply(this, arguments); 
  7.     }, time); 
  8.   } 
  9. }; 
  10. 復(fù)制代碼 

防抖常應(yīng)用于用戶進(jìn)行搜索輸入節(jié)約請(qǐng)求資源,window觸發(fā)resize事件時(shí)進(jìn)行防抖只觸發(fā)一次。

12.throttle(節(jié)流)
高頻時(shí)間觸發(fā),但n秒內(nèi)只會(huì)執(zhí)行一次,所以節(jié)流會(huì)稀釋函數(shù)的執(zhí)行頻率。

  1. const throttle = (fn, time) => { 
  2.   let flag = true
  3.   return function() { 
  4.     if (!flag) return
  5.     flag = false
  6.     setTimeout(() => { 
  7.       fn.apply(this, arguments); 
  8.       flag = true
  9.     }, time); 
  10.   } 
  11. 復(fù)制代碼 

節(jié)流常應(yīng)用于鼠標(biāo)不斷點(diǎn)擊觸發(fā)、監(jiān)聽滾動(dòng)事件。

13.函數(shù)珂里化

  1. 指的是將一個(gè)接受多個(gè)參數(shù)的函數(shù) 變?yōu)?nbsp;接受一個(gè)參數(shù)返回一個(gè)函數(shù)的固定形式,這樣便于再次調(diào)用,例如f(1)(2) 

經(jīng)典面試題:實(shí)現(xiàn)add(1)(2)(3)(4)=10; 、 add(1)(1,2,3)(2)=9;

  1. function add() { 
  2.   const _args = [...arguments]; 
  3.   function fn() { 
  4.     _args.push(...arguments); 
  5.     return fn; 
  6.   } 
  7.   fn.toString = function() { 
  8.     return _args.reduce((sum, cur) => sum + cur); 
  9.   } 
  10.   return fn; 
  11. 復(fù)制代碼 

14.模擬new操作
3個(gè)步驟:

  1. 以ctor.prototype為原型創(chuàng)建一個(gè)對(duì)象。
  2. 執(zhí)行構(gòu)造函數(shù)并將this綁定到新創(chuàng)建的對(duì)象上。
  3. 判斷構(gòu)造函數(shù)執(zhí)行返回的結(jié)果是否是引用數(shù)據(jù)類型,若是則返回構(gòu)造函數(shù)執(zhí)行的結(jié)果,否則返回創(chuàng)建的對(duì)象。
  1. function newOperator(ctor, ...args) { 
  2.   if (typeof ctor !== 'function') { 
  3.     throw new TypeError('Type Error'); 
  4.   } 
  5.   const obj = Object.create(ctor.prototype); 
  6.   const res = ctor.apply(obj, args); 
  7.  
  8.   const isObject = typeof res === 'object' && res !== null
  9.   const isFunction = typeof res === 'function'
  10.   return isObject || isFunction ? res : obj; 
  11. 復(fù)制代碼 

15.instanceof
instanceof運(yùn)算符用于檢測(cè)構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在某個(gè)實(shí)例對(duì)象的原型鏈上。

  1. const myInstanceof = (leftright) => { 
  2.   // 基本數(shù)據(jù)類型都返回false 
  3.   if (typeof left !== 'object' || left === nullreturn false
  4.   let proto = Object.getPrototypeOf(left); 
  5.   while (true) { 
  6.     if (proto === nullreturn false
  7.     if (proto === right.prototype) return true
  8.     proto = Object.getPrototypeOf(proto); 
  9.   } 
  10. 復(fù)制代碼 

16.原型繼承
這里只寫寄生組合繼承了,中間還有幾個(gè)演變過來的繼承但都有一些缺陷

  1. function Parent() { 
  2.   this.name = 'parent'
  3. function Child() { 
  4.   Parent.call(this); 
  5.   this.type = 'children'
  6. Child.prototype = Object.create(Parent.prototype); 
  7. Child.prototype.constructor = Child; 
  8. 復(fù)制代碼 

 

 

責(zé)任編輯:姜華 來源: 前端UpUp
相關(guān)推薦

2021-06-09 07:01:30

前端CallApply

2021-07-15 14:29:06

LRU算法

2021-09-06 08:13:35

APM系統(tǒng)監(jiān)控

2021-05-18 07:52:31

PromiseAsyncAwait

2024-08-06 10:16:52

Java AgentJava

2020-09-15 08:55:07

算法數(shù)據(jù)基礎(chǔ)

2020-09-17 14:04:32

拷貝

2024-12-03 16:49:58

2023-08-02 08:54:58

Java弱引用鏈表

2023-06-25 08:38:09

多線程循環(huán)打印

2020-09-16 14:17:42

flat方法

2021-10-31 07:38:37

排序算法代碼

2023-09-18 09:10:11

Golang高性能緩存庫

2025-04-01 08:25:00

OSPF網(wǎng)絡(luò)IT

2019-11-26 10:30:11

CSS前端面試題

2015-08-21 10:38:16

編程語言GoC語言

2025-04-03 09:56:40

Python算法開發(fā)

2022-04-15 09:23:29

Kubernetes面試題

2021-02-23 12:43:39

Redis面試題緩存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)