摘要:最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現,。后面以這道題為引線面試官可能會追問什么是執行上下文的判斷,的區別手寫一個函數實現斐波那契數列首先拷一個阮神在他教程里的一個寫法。
最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現bind,promise。手寫ajax,手寫一些算法。
翻閱了很多書籍和博客。
這里做一個總結改進,算是對我后面大概為期一個月找工作的準備。
手寫實現bind()Function.prototype._bind = function (context) { var self = this; var args = Array.prototype.slice.call(arguments, 1); var fBind = function () { var bindArgs = Array.prototype.slice.call(arguments); return self.apply(this instanceof fBind ? this : context, args.concat(bindArgs)); } fBind.prototype = self.prototype&&Object.create(self.prototype) return fBind; }
簡單的說明:
這里之所以傳參的時候需要兩個數組,是因為考慮到用new以構造函數的形式調用硬綁定函數的情況:this這時是應該指向實例對象的。
這樣子就需要繼承之前函數的方法, fBind.prototype = self.prototype&&Object.create(self.prototype)
,同時也可以用 Object.setPrototypeOf(fBind.prototype,self.prototype)。
考慮到存在undefined的情況,前面加一個判斷self.prototype&&.....
關于apply的第一個參數,如果考慮到之前的情況,是不能傳入context的,這需要做一個判斷。
像是下面的情況
function Foo(price){ this.price =price this.fn = ()=>{ console.log("hi fn") } console.log(this.name) } Foo.prototype.sayMyName = function(){ console.log(this.name) } var Obj1 = { name:"obj1" } var b =Foo._bind(Obj1) b() //"obj1" var c = new b(1000)//"i am c" c.name = "i am c" c.sayMyName()
這里的this的指向就是c,它指向實例對象本身。
后面以這道題為引線面試官可能會追問:
什么是執行上下文
this的判斷
call,bind的區別
手寫一個函數實現斐波那契數列首先拷一個阮神在他es6教程里的一個寫法。
function* fibonacci() { let [prev, curr] = [0, 1]; for (;;) { yield curr; [prev, curr] = [curr, prev + curr]; } } for (let n of fibonacci()) { if (n > 1000) break; console.log(n); }
更精簡的
const feibo= max=>{ let [a,b,i]= [0,1,1] while(i++<=max) { [a,b] = [b,a + b ] console.log(b) } return a }
相對是非常簡單的,感覺也不會多問啥,就不多說了。
手寫一個簡單的ajaxlet xhr = new XMLHttpRequest() xhr.open("get", url, true) xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ console.log("請求完成") if(this.status >= 200 &&this.status<300){ conso.log("成功") }else{ consol.log("失敗") } } } xhr.onerror = function(e) { console.log("連接失敗") } xhr.send()
大概是這么個意思就差不多了,順勢可能會問一些狀態碼和狀態值的問題,或者直接問到關于http上面的問題。
原型繼承function inherit(supertype,subtype){ Object.setPrototypeOf(subtype.prototype,supertype.prototype) subtype.prototype.constructor = subtype } function Car(name,power){ this.name=name this.power = power } Car.prototype.showPower = function(){ console.log(this.power) } function Changan(price,name,power){ this.price = price Car.call(this,name,power) } inherit(Car,Changan) Changan.prototype.showName = function(){ console.log(this.name) } var star = new Changan(100000,"star",500) star.showPower()防抖與節流
function debounce(fn,duration){ var timer window.clearTimeout(timer) timer = setTimeout(()=>{ fn.call(this) },duration) } function throttle(fn,duration){ let canIRun if(!canIRun)return fn.call(this) canIRun = false setTimeout(()=>{ canIRun = true },duration) }數組去重
我一般就用這兩種,大部分情況都能應付了。
[...new Set(array)]
//hash function unique(array) { const object = {} array.map(number=>{ object[number] = true }) return Object.keys(object).map(//.......) }//大概是這樣的意思,寫法根據數組的不同可能會有所改變深拷貝
應該是面試里面手寫xxx出現頻率最高的題了,無論是筆試還是面試。
總是讓你手寫實現深拷貝函數。
事實上,js并不能做到真正完全的標準的深拷貝
所以不管你寫什么樣的深拷貝函數都會有不適用的地方,這取決于使用的場景和拷貝的對象,如果面試官在這上面鉆研比較深的話,是很難做到完美的。
既然這樣就寫個將就一點的深拷貝吧,面向面試的那種。
function deepClone(item) { return result; }
首先在類型判斷上做一個選擇,一般情況來說,用new創建的實例對象用typeof判斷會出問題的,相比之下instanceof也不靠譜。這里面相對比較靠譜的Object.prototype.toString.call(item)。(這個其實也不兼容到全部情況和性能要求,但是面向面試代碼可讀性會高一點)。
type = Object.prototype.toString.call(item).slice(8,this.length-1), //[object String],[object Array],[object Object]
函數的拷貝,這里不能使用bind,會改變this指向或影響后續使用call調用該拷貝的函數,大部分情況是不必要的,這里就直接賦值吧。
于是這里可以把基本數據類型和Function放一起。
fk= ["String","Number","Boolean","Function"].indexOf(type)>-1
dom對象的拷貝: result = item.cloneNode(true);
忽略正則
Date,[object Object], [object Array]放到后面的判斷
let other = { //需要遞歸或者其他的操作 Array() { result = [] item.forEach((child, index)=>{ hash.set(item, result); result[index] = deepClone(child,hash) }) }, Date(){ result = new Date(item) }, Object(){ result = {} Reflect.ownKeys(item).forEach(child=>{ hash.set(item, result); result[child] = deepClone(item[child],hash) }) } } other[type]()
這樣子是不是相對清晰一些了,應付一般的情況應該差不多了,但是沒考慮循環引用。
這里給個思路是使用ES6的WeakMap,不知道的兄弟可以看看阮神的ES6博客,為防止爆棧,我把循環引用直接扔給它,完美拷貝。
就相當于
var wm = new WeakMap() var obj = { name:null } obj.name = obj wm.set(obj,wm.get(obj)) console.log(wm)
現在就需要在開頭檢查一下循環引用,然后直接返回WeakMap對象鍵名為item參數對象的值
所以最終代碼就是
function deepClone(item,hash = new WeakMap()) { if (!item) return item if (hash.has(item))return hash.get(item); //檢查循環引用 var result, type = Object.prototype.toString.call(item).slice(8,this.length-1), fk= ["String","Number","Boolean","Function"].indexOf(type)>-1 if(fk){ result = item;//直接賦值 }else if(item.nodeType && typeof item.cloneNode === "function"){ result = item.cloneNode(true); //是否是dom對象 }else{ let other = { //需要遞歸或者其他的操作 Array() { result = [] item.forEach((child, index)=>{ hash.set(item, result); result[index] = deepClone(child,hash) }) }, Date(){ result = new Date(item) }, Object(){ result = {} Reflect.ownKeys(item).forEach(child=>{ hash.set(item, result); result[child] = deepClone(item[child],hash) }) } } other[type]() } return result; }
意思就大概是這個意思,當然深拷貝的方法有很多,甚至不一定用到遞歸。面試官總會有找茬的地方的。
我覺得我寫的這個還是滿足我現在找工作的級別要求的。
然后是我用來測試的對象
var obj1 = { name:"obj1", one : { a:new Date(), b:new String("1-2"), c:new Array(["this","is",1,{a:23}]), d: function () { if(true){ return "d" } }, e:new Number(15), f:new Boolean(true) }, two(x){ console.log(x+" "+this.name) }, three : [ { a:"this is a", b:document.body, c:{ a:[1,2,3,4,5,[13,[3],true],10], b:{ a:{ a:[1,2,3] }, b:2 } } }, ], four:[1,2] } obj1.name=obj1 obj1.four[3] = obj1 var copy = deepClone(obj1) console.log(copy) copy.two.call(window,"hi")
## new
簡單說下大概是這么一個過程
創建一個空對象
執行傳入的構造函數,執行過程中對 this 操作就是對 這個空對象 進行操作。
返回這個空對象
模擬需要考慮的問題
是一個空對象,這里面的寫法obj原型鏈是沒有上一級的,即不存在與其他任何對象之間的聯系,雖然在這里面沒多少區別:var obj = Object.create(null),
this指向這個空對象:let rt = Constructor.apply(obj, arguments);
可以訪問構造函數的原型鏈, Object.setPrototypeOf(obj, Constructor.prototype);
如果構造函數有返回值,并且是一個對象,那么實例對象拿到的就是這個對象(應該只是值,并不是引用)。所以這里要做個判斷return typeof rt === "object" ? rt : obj;
最終的代碼
function _new(){ var obj = Object.create(null), Constructor = [].shift.call(arguments); Object.setPrototypeOf(obj, Constructor.prototype); let rt = Constructor.apply(obj, arguments); return rt instanceof Object ? rt : obj; }
快排
:代碼精簡了一點
function quickSort(arr){ if(arr.length<=1)return arr var index = Math.floor(arr.length/2), number = arr.splice(index,1)[0], left = [], right = []; arr.forEach(item=>{ item<=number?left.push(item):right.push(item) }) return quickSort(left).concat([number],quickSort(right)) }
這期間會不斷更新并修改,這里面的手寫實現您如果有更好的寫法或者新的思路,也希望可以說明交流。最后謝謝大佬些的觀看。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103597.html
摘要:第一天寫文章,心里難免有些小激動,希望能堅持下去,有輸出才有更好的輸入。用戶選擇完之后,我會得到一個時間戳的數組這里呢我們先需要看一下的語法。 第一天寫文章,心里難免有些小激動,希望能堅持下去,有輸出才有更好的輸入。 reduce這個方法最初我是在面試題里看見的有一個長度為100的數組,請以優雅的方式求出該數組的前10個元素之和?答案如下 var a = [1, 2, 3, 4, 5...
摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關問題,其他公司壓根沒問。我自己回答的是自己開發組件面臨的問題。完全不用擔心對方到時候打電話核對的問題。 2019的5月9號,離發工資還有1天的時候,我的領導親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經是第2個月沒工資了。 公...
摘要:那既然頻繁出,肯定不能是手撕紅黑樹我覺得面試官也多半撕不出來,不撕紅黑樹,那這道題還有點救,慢慢往下看。簡單說來說,哈希表由兩個要素構成桶數組和散列函數。所謂的哈希沖突,就是不同的經過哈希函數計算,落到了同一個下標。快手面試官真的嗎我不信。手寫HashMap?這么狠,面試都卷到這種程度了?第一次見到這個面試題,是在某個不方便透露姓名的Offer收割機大佬的文章:這……我當時就麻了,我們都知道...
摘要:前言得益于金三銀四,在最近一段時間,面試了一些人,但是符合的寥寥無幾。看到我的面試題自己寫的面試題,自己想的答案。聽人說過一個面試套路面試官問的問題,可能面試官自己都不懂,目的只是為了壓工資,挫士氣。不過我是為了測試面試者是不是真的精通。 技術在不斷的創新,隨著框架,庫,構建工具,打包工具,版本控制工具等操作越來越方便,使用越來越簡單。面對這樣的情況,除了興奮,也要警惕。這些工具使得開...
閱讀 3017·2023-04-26 00:32
閱讀 498·2019-08-30 15:52
閱讀 2105·2019-08-30 15:52
閱讀 3347·2019-08-30 15:44
閱讀 3280·2019-08-30 14:09
閱讀 1416·2019-08-29 15:15
閱讀 3390·2019-08-28 18:12
閱讀 1074·2019-08-26 13:55