本文分享 12 道高頻JavaScript的面試題,包含手寫以及經常使用的正則。前端
防抖函數原理 : 在事件被觸發n秒後在執行回調,若是在這n秒內又被觸發,則從新計時。node
那麼與節流函數的區別直接看這個動畫實現便可。 面試
手寫簡化版設計模式
//防抖函數 const debounce = (fn,delay)=>{ let timer = null; return (...args)=>{ clearTimeout(timer); timer = setTimeout(()=>{ fn.apply(this,args) },delay); }; }; 複製代碼
適用場景 :數組
生存環境請用lodash.debounce瀏覽器
防抖函數原理:規定在一單位時間內。只能觸發一次函數。若是這個單位時間內觸發屢次函數,只有一次生效。bash
//手寫簡化版markdown
//節流函數 const throttle = (fn,delay = 500) =>{ let flag = true; return (...args) =>{ if (!flag) return; flag = false; setTimeout(() => { fn.apply(this,args) },delay); }; }; 複製代碼
適用場景:app
簡單版 :dom
const newObj = JSON.parse(JSON.stringify(oldObj));
複製代碼
侷限性 : 一、他沒法實現函數、RegExp等特殊對象的克隆
二、會拋棄對象的constructor,全部的構造函數會指向Object
三、對象有循環引用,會報錯
event bus既是node中各個模塊的基石,又是前端組件通訊的依賴手段之一,同時涉及了訂閱-發佈設計模式,是很是重要的基礎。
簡單版:
class EventEmeitter { constructor(){ this._events = this._events || new Map(); //儲存事件/回調鍵值對 this._maxListeners = this._maxListeners || 1o;//設立監聽上限 } } //觸發名爲type的事件 EventEmeitter.prototype.emit = function(type,...args){ let hander; //從儲存事件鍵值對的this._events中獲取對應事件回調函數 handler = this._events.get(type); if (args.length > 0) { hander.apply(this,args); }else{ handler.call(this); } return true; }; //監聽名爲type事件 EventEmeitter.prototype.addListener = function(type,fn) { //將type事件以及對應的fn函數放入this._events中儲存 if (!this._events.get(type)) { this._events.set(type,fn); } }; 複製代碼
//模擬 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) // 這裏重點 : 當 O 嚴格等於 L 時,返回 true return true; L = L.__proto__; } } 複製代碼
new操做符作了這些事:
// 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; } 複製代碼
call作了什麼 :
//模擬 call bar.mycall(null); //實現一個call方法; Function.prototype.myCall = function(context){ //此處沒有考慮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; }; 複製代碼
apply原理與call很類似,很少獒數
//模擬 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; } 複製代碼
實現bind要作什麼
// mdn的實現 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時,說明返回的fBound被當作new的構造函數調用 return fToBind.apply(this instanceof fBound ? this : oThis, // 獲取調用時(fBound)的傳參.bind 返回的函數入參每每是這麼傳遞的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 維護原型關係 if (this.prototype) { } // 下行的代碼使fBound.prototype是fNOP的實例,所以 // 返回的fBound若做爲new的構造函數,new生成的新對象做爲this傳入fBound,新對象的__proto__就是fNOP的實例 fBound.prototype = new fNOP(); return fBound; }; } 複製代碼 詳解請移步JavaScript深刻之bind的模擬實現 #12 模擬Object.create Object.create()方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。 // 模擬 Object.create function create(proto) { function F() {} F.prototype = proto; return new F(); } 複製代碼
Object.create() 方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。
// 模擬 object.create function create(proto){ function F(){ F.prototype = proto; return new F(); } } 複製代碼
let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled'; parseParam(url) /* 結果 { user: 'anonymous', id: [ 123, 456 ], // 重複出現的 key 要組裝成數組,能被轉成數字的就轉成數字類型 city: '北京', // 中文需解碼 enabled: true, // 未指定值得 key 約定爲 true } */ 複製代碼
var s1 = "get-element-by-id" //轉化爲 getElementById 複製代碼
var f = function(s){ return s.replace(/-\w/g,function(x){ return x.slice(1).toUpperCase(); }) } 複製代碼