2020年12道高頻JavaScript手寫(xiě)面試題及答案

JavaScript筆試部分
本文分享 12 道高頻JavaScript的面試題,包含手寫(xiě)以及常用的正則。
實(shí)現(xiàn)防抖函數(shù) (debounce)
防抖函數(shù)原理 : 在事件被觸發(fā)n秒后在執(zhí)行回調(diào),如果在這n秒內(nèi)又被觸發(fā),則重新計(jì)時(shí)。
那么與節(jié)流函數(shù)的區(qū)別直接看這個(gè)動(dòng)畫(huà)實(shí)現(xiàn)即可。
手寫(xiě)簡(jiǎn)化版
//防抖函數(shù) const debounce = (fn,delay)=>{ let timer = null; return (...args)=>{ clearTimeout(timer); timer = setTimeout(()=>{ fn.apply(this,args) },delay); }; };
適用場(chǎng)景 :
- 按鈕提交場(chǎng)景: 防止多次提交按鈕,只執(zhí)行最后提交的一次
- 服務(wù)端驗(yàn)證場(chǎng)景 : 表單驗(yàn)證需要服務(wù)端配合,只執(zhí)行一段連續(xù)的輸入事件的最后一次,還有搜索聯(lián)想詞功能類(lèi)似
生存環(huán)境請(qǐng)用lodash.debounce
實(shí)現(xiàn)節(jié)流函數(shù) (throttle)
防抖函數(shù)原理:規(guī)定在一單位時(shí)間內(nèi)。只能觸發(fā)一次函數(shù)。如果這個(gè)單位時(shí)間內(nèi)觸發(fā)多次函數(shù),只有一次生效。
//手寫(xiě)簡(jiǎn)化版 //節(jié)流函數(shù) const throttle = (fn,delay = 500) =>{ let flag = true; return (...args) =>{ if (!flag) return; flag = false; setTimeout(() => { fn.apply(this,args) },delay); }; };
適用場(chǎng)景:
- 拖拽場(chǎng)景: 固定時(shí)間內(nèi)只執(zhí)行一次,防止超高頻次觸發(fā)位置變動(dòng)
- 縮放場(chǎng)景: 監(jiān)控瀏覽器resize
- 動(dòng)畫(huà)場(chǎng)景: 避免短時(shí)間內(nèi)多次觸發(fā)動(dòng)畫(huà)引起性能問(wèn)題
深克隆 (deepclone)
簡(jiǎn)單版 :
const newObj = JSON.parse(JSON.stringify(oldObj));
局限性 :
1、他無(wú)法實(shí)現(xiàn)函數(shù)、RegExp等特殊對(duì)象的克隆
2、會(huì)拋棄對(duì)象的constructor,所有的構(gòu)造函數(shù)會(huì)指向Object
3、對(duì)象有循環(huán)引用,會(huì)報(bào)錯(cuò)
實(shí)現(xiàn)Event (event bus)
event bus既是node中各個(gè)模塊的基石,又是前端組件通信的依賴(lài)手段之一,同時(shí)涉及了訂閱-發(fā)布設(shè)計(jì)模式,是非常重要的基礎(chǔ)。
簡(jiǎn)單版:
class EventEmeitter { constructor(){ this._events = this._events || new Map(); //儲(chǔ)存事件/回調(diào)鍵值對(duì) this._maxListeners = this._maxListeners || 1o;//設(shè)立監(jiān)聽(tīng)上限 } } //觸發(fā)名為type的事件 EventEmeitter.prototype.emit = function(type,...args){ let hander; //從儲(chǔ)存事件鍵值對(duì)的this._events中獲取對(duì)應(yīng)事件回調(diào)函數(shù) handler = this._events.get(type); if (args.length > 0) { hander.apply(this,args); }else{ handler.call(this); } return true; }; //監(jiān)聽(tīng)名為type事件 EventEmeitter.prototype.addListener = function(type,fn) { //將type事件以及對(duì)應(yīng)的fn函數(shù)放入this._events中儲(chǔ)存 if (!this._events.get(type)) { this._events.set(type,fn); } };
實(shí)現(xiàn)instanceOf
//模擬 instanceof function instance_of(L,R){ var O = R.prototype;//取 R 的顯示原型 L = L.__proto__;//取 L 的隱式原型 while (true) { if (L === null) return false; if (O === L) // 這里重點(diǎn) : 當(dāng) O 嚴(yán)格等于 L 時(shí),返回 true return true; L = L.__proto__; } }
模擬new
new操作符做了這些事:
- 他創(chuàng)建了一個(gè)全新的對(duì)象
- 他會(huì)被執(zhí)行[[Prototype]] (也就是__proto__) 鏈接
- 它使this指向新創(chuàng)建的對(duì)象
- 通過(guò)new創(chuàng)建的每個(gè)對(duì)象將最終被[[Prototype]]鏈接到這個(gè)函數(shù)的prototype對(duì)象上
- 如果函數(shù)沒(méi)有返回對(duì)象類(lèi)型Object(包含F(xiàn)unction,Array,Date,RegExg,Error),那么new表達(dá)式中的函數(shù)調(diào)用將返回對(duì)象引用
// objectFactory(name,'cxk','18') function objectFactory(){ const obj = new object(); const Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; const ret = Constructor.apply(obj,arguments); return typeof ret === "object" ? ret : obj; }
實(shí)現(xiàn)一個(gè)call
call做了什么 :
- 將函數(shù)設(shè)為對(duì)象的屬性
- 執(zhí)行&刪除這個(gè)函數(shù)
- 指定this到函數(shù)并傳人給定參數(shù)執(zhí)行函數(shù)
- 如果不傳人參數(shù),默認(rèn)指向?yàn)?window
//模擬 call bar.mycall(null); //實(shí)現(xiàn)一個(gè)call方法; Function.prototype.myCall = function(context){ //此處沒(méi)有考慮context非object情況 context.fn = this; let args = []; for (let i = 1,len = arguments.length,i < len; i++){ args.push(arguments[i]); } context.fn(...args); let result = context.fn(...args); delete context.fn; return result; };
實(shí)現(xiàn)apply方法
apply原理與call很相似,不多獒數(shù)
//模擬 apply Function.prototype.myapply = function(context,arr){ var context = Object(context) || window; context.fn = this; var result; if (!arr){ result = context.fn(); }else{ var args = []; for (var i = 0,len = arr.length;i < len; i++){ args.push("arr["+ i +"]"); } result = eval("context.fn("+ args + ")"); } delete context.fn; return result; }
實(shí)現(xiàn)bind
實(shí)現(xiàn)bind要做什么
- 返回一個(gè)函數(shù),綁定this,傳遞預(yù)置參數(shù)
- bind返回的函數(shù)可以作為構(gòu)造函數(shù)使用。故作為構(gòu)造函數(shù)時(shí)應(yīng)使得this失效,但是傳人的參數(shù)依然有效
// mdn的實(shí)現(xiàn) if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // this instanceof fBound === true時(shí),說(shuō)明返回的fBound被當(dāng)做new的構(gòu)造函數(shù)調(diào)用 return fToBind.apply(this instanceof fBound ? this : oThis, // 獲取調(diào)用時(shí)(fBound)的傳參.bind 返回的函數(shù)入?yún)⑼沁@么傳遞的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 維護(hù)原型關(guān)系 if (this.prototype) { } // 下行的代碼使fBound.prototype是fNOP的實(shí)例,因此 // 返回的fBound若作為new的構(gòu)造函數(shù),new生成的新對(duì)象作為this傳入fBound,新對(duì)象的__proto__就是fNOP的實(shí)例 fBound.prototype = new fNOP(); return fBound; }; }
詳解請(qǐng)移步JavaScript深入之bind的模擬實(shí)現(xiàn) #12
模擬Object.create
Object.create()方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的__proto__。 // 模擬 Object.create function create(proto) { function F() {} F.prototype = proto; return new F(); }
模擬Object.create
Object.create() 方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的__proto__。
// 模擬 object.create function create(proto){ function F(){ F.prototype = proto; return new F(); } }
解析 URL Params為對(duì)象
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; parseParam(url) /* 結(jié)果 { user: 'anonymous', id: [ 123, 456 ], // 重復(fù)出現(xiàn)的 key 要組裝成數(shù)組,能被轉(zhuǎn)成數(shù)字的就轉(zhuǎn)成數(shù)字類(lèi)型 city: '北京', // 中文需解碼 enabled: true, // 未指定值得 key 約定為 true } */
轉(zhuǎn)化為駝峰命名
var s1 = "get-element-by-id" //轉(zhuǎn)化為 getElementById
var f = function(s){ return s.replace(/-\w/g,function(x){ return x.slice(1).toUpperCase(); }) }
本文主要是一些基礎(chǔ)知識(shí),希望能幫助那些基礎(chǔ)不太好的同行們。加油~~~~~~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
新手怎么學(xué)JS?JavaScript基礎(chǔ)語(yǔ)法入門(mén)要學(xué)什么?
這篇文章主要介紹了新手怎么學(xué)JS?JavaScript基礎(chǔ)語(yǔ)法入門(mén)要學(xué)什么?本文給大家介紹一個(gè)大致的學(xué)習(xí)路線(xiàn)和方向,需要的朋友趕緊一起來(lái)看看吧2020-03-19- 這篇文章主要介紹了javascript作用域,作用域鏈,閉包的面試題,在一些前端面試中經(jīng)常會(huì)問(wèn)題,今天小編特此整理分享到腳本之家平臺(tái),需要的朋友可以參考下2020-02-21
JavaScript關(guān)于數(shù)組的四道面試題
這篇文章主要介紹了JavaScript關(guān)于數(shù)組的四道面試題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)2019-12-2311道JS選擇題(聽(tīng)說(shuō)第一題就難倒80%的人)
這篇文章主要介紹了11道JS選擇題(聽(tīng)說(shuō)第一題就難倒80%的人),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-12-18- JS 初學(xué)者總是對(duì)this關(guān)鍵字感到困惑,因?yàn)榕c其他現(xiàn)代編程語(yǔ)言相比,JS 中的這this關(guān)鍵字有點(diǎn)棘手。今天小編給大家?guī)?lái)10個(gè)比較流行的JavaScript面試題 ,感興趣的朋友一起2019-07-12
- 這篇文章主要介紹了10個(gè)JavaScript筆試題解析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2020-06-02