摘要:實(shí)際上是一個(gè)讓出線程的標(biāo)志遇到會(huì)立即返回一個(gè)狀態(tài)的。一個(gè)簡(jiǎn)單的防抖函數(shù)如果定時(shí)器存在則清除重新開(kāi)始定時(shí)執(zhí)行缺點(diǎn)只能在最后執(zhí)行,不能立即被執(zhí)行,在某些情況下不適用。假設(shè)壓入棧的所有數(shù)字均不相等。接收數(shù)據(jù)不受同源政策限制。
開(kāi)始
盡管秋招還沒(méi)有拿到offer(好難過(guò)),但是一些知識(shí)點(diǎn)還是要總結(jié)的,既然自己選了這條路,那就一定要堅(jiān)定不移的走下去......
注意 new 運(yùn)算符的優(yōu)先級(jí)function Foo() { return this; } Foo.getName = function () { console.log("1"); }; Foo.prototype.getName = function () { console.log("2"); }; new Foo.getName(); // -> 1 new Foo().getName(); // -> 2
通過(guò)這段代碼可以看出:new Foo() 的優(yōu)先級(jí)高于 new Foo.
對(duì)于代碼1 來(lái)說(shuō):是將 Foo.getName 當(dāng)成一個(gè)構(gòu)造函數(shù)來(lái)執(zhí)行,執(zhí)行構(gòu)造函數(shù)所以輸出為1.
對(duì)于代碼2來(lái)說(shuō):通過(guò) new Foo() 創(chuàng)建了一個(gè)Foo的實(shí)例,通過(guò)實(shí)例訪問(wèn)其原型鏈上的 方法所以輸出為2.
注意非匿名的立即執(zhí)行函數(shù)var foo = 1; // 有名立即執(zhí)行函數(shù) (function foo() { foo = 10; console.log(foo); })(); // 執(zhí)行這段代碼會(huì)輸出什么呢? // -> ? foo() { foo = 10 ; console.log(foo) } // 再去訪問(wèn) foo 的值 foo // -> 1
當(dāng)JS執(zhí)行器遇到非匿名的立即執(zhí)行函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)輔助的特定對(duì)象,然后將函數(shù)名稱作為這個(gè)對(duì)象的屬性,因此行數(shù)內(nèi)部才可以訪問(wèn)到 foo ,但這個(gè)值是只讀的,所以對(duì)其重新賦值不會(huì)生效,所以打印結(jié)果還是這個(gè)函數(shù),并且外部的值也沒(méi)有發(fā)生改變。
關(guān)于對(duì)象的深拷貝
可以使用 JSON.stringify 和 JSON.parse 這個(gè)兩個(gè)方法
優(yōu)點(diǎn):簡(jiǎn)單
缺點(diǎn):會(huì)忽略掉 undefined ; 不能序列化函數(shù) ; 不能解決循環(huán)引用的對(duì)象
function clone(obj) { return JSON.parse(JSON.stringify(obj)); }
使用遞歸循環(huán)賦值的方式
優(yōu)點(diǎn):可以處理 undefined、函數(shù)等各種情況
缺點(diǎn):實(shí)現(xiàn)相對(duì)麻煩,效率不高
function clone(obj) { if(!obj || typeof obj !== "object") { return; } var _obj = obj.constructor === Object ? {} : []; for(let key in obj) { if(typeof obj[key] === "object") { _obj[key] = clone(obj[key]); } else { _obj[key] = obj[key]; } } return _obj; } // 或者 function clone(obj) { if(!obj || typeof obj !== "object") throw new TypeError("params typeError"); let _obj = obj.constructor === Object ? {} : []; Object.getOwnPropertyNames(obj).forEach(name => { if(typeof obj[name] === "object") { _obj[name] = clone(obj[name]); } else { _obj[name] = obj[name]; } }); return _obj; }
使用內(nèi)置 MessageChannel 對(duì)象
優(yōu)點(diǎn):是內(nèi)置函數(shù)中處理深拷貝性能最快的
缺點(diǎn):不能處理函數(shù)(會(huì)報(bào)錯(cuò))
function clone(obj) { return new Promise(resolve => { let {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } clone(obj).then(console.log);關(guān)于async/await , promise 異步執(zhí)行順序
想解決這個(gè)問(wèn)題,就必須知道 `await` 做了什么?
剛開(kāi)始以為 await 會(huì)一直等待表達(dá)執(zhí)行的執(zhí)行結(jié)果,之后才會(huì)執(zhí)行后面的代碼。實(shí)際上 await 是一個(gè)讓出線程的標(biāo)志(遇到 await 會(huì)立即返回一個(gè) pending 狀態(tài)的promise)。await后面的函數(shù)會(huì)先執(zhí)行一遍,然后就會(huì)跳出整個(gè) async 函數(shù)來(lái)執(zhí)行后面js代碼。等本輪事件循環(huán)執(zhí)行完又跳回到 async 函數(shù)中等待await后面表達(dá)式的返回值,如果返回值為非 promise 則繼續(xù)執(zhí)行async后面的代碼,否則將 promse 加入隊(duì)列。
且看一道面試題(分析代碼執(zhí)行 順序):
async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } console.log("script start"); setTimeout(function () { console.log("settimeout"); },0); async1(); new Promise(function (resolve) { console.log("promise1"); resolve(); }).then(function () { console.log("promise2"); }); console.log("script end");
OK,那接下來(lái)具體分析執(zhí)行過(guò)程:
首先輸出 "script start" ,然后立即將定時(shí)器加入異步事件隊(duì)列。執(zhí)行 async1() ,輸出 "async1 start" ,進(jìn)入 async2() ,輸出 "async2" ,跳出整個(gè) async1() 函數(shù)來(lái)執(zhí)行后面js代碼,執(zhí)行promise執(zhí)行器中的內(nèi)容,輸出 "promise1" ,執(zhí)行resolve()回調(diào),將then函數(shù)中的內(nèi)容加入異步事件隊(duì)列,接著輸出 "script end" ?;氐?async1() 的await等待 async2() 函數(shù)的返回值,因?yàn)榉祷刂凳且粋€(gè)promise實(shí)例,將promise加入異步事件隊(duì)列。此時(shí)的同步代碼執(zhí)行完畢,輪詢并從隊(duì)列拿出代碼放入主線程執(zhí)行,所以輸出 "promise2" ,繼續(xù)執(zhí)行 async1() 中的后續(xù)內(nèi)容,輸出 "async1 end" ,最后取出定時(shí)器中的內(nèi)容并執(zhí)行,輸出 "settimeout" 。
綜上所述:
script start async1 start async2 promise1 script end promise2 async1 end settimeout
那么再看一個(gè)例子應(yīng)該會(huì)簡(jiǎn)單很多:
function testFunc() { console.log("testFunc..."); // 2 return "testFunc"; } async function testAsync() { console.log("testAsync..."); // 7 return Promise.resolve("hello testAsync"); } async function foo() { console.log("test start..."); // 1 const v1 = await testFunc(); connsole.log("hello world."); // 5 console.log(v1); // 6 testFunc const v2 = await testAsync(); console.log(v2); // 9 hello testAsync } foo(); var promise = new Promise(resolve => { console.log("promise start.."); // 3 resolve("promise"); }); promise.then(val => console.log(val)); // 8 promise console.log("test end..."); // 4防抖和節(jié)流
防抖:如果用戶多次調(diào)用且間隔小于wait值,那么就會(huì)被轉(zhuǎn)化為一次調(diào)用。
節(jié)流:多次執(zhí)行函數(shù)轉(zhuǎn)化為,每隔一定時(shí)間(wait)調(diào)用函數(shù) 。
一個(gè)簡(jiǎn)單的防抖函數(shù):
function debounce(func, wait) { let timer = null; return function(...params) { // 如果定時(shí)器存在則清除 if(timer){ clearTimeout(timer); } // 重新開(kāi)始定時(shí)執(zhí)行 timer = setTimeout(() => { func.apply(this, params); }, wait); } }
缺點(diǎn):只能在最后執(zhí)行,不能立即被執(zhí)行,在某些情況下不適用。
改進(jìn)...
function debounce(func, wait, immediate) { let timer, context, args; // 定時(shí)器 let later = function() { return setTimeout(() => { timer = null; if(!immediate) { func.apply(context, args); } }, wait); } return function(...params) { if(!timer) { timer = later(); // immediate 為 true,則立即執(zhí)行 // 否則 緩存上下文 和 參數(shù) if(immediate) { func.apply(this, params); } else { context = this; args = params; } } else { clearTimeout(timer); timer = later(); } } }
一個(gè)簡(jiǎn)單的節(jié)流函數(shù):
// 節(jié)流函數(shù) // 快速的多次執(zhí)行,轉(zhuǎn)化為等待wait時(shí)間再去執(zhí)行 function throttle(func, wait) { var timer = null; var context = null; return function(...args) { context = this; if(!timer) { timer = setTimeout(function() { timer = null; func.apply(context, args); }, wait); } } } // 如果想讓第一次調(diào)用立即執(zhí)行也非常簡(jiǎn)單 僅需要將 func.apply(context, args) 提到定時(shí)器外邊即可。
節(jié)流函數(shù)除了可以使用定時(shí)器實(shí)現(xiàn)以外,當(dāng)然也可以有其他方式:
// 第一次調(diào)用會(huì)被立即執(zhí)行 function throttle(func, wait) { var prev = 0; var context = null; return function(...args) { var now = +new Date(); context = this; if(now -prev > wait) { func.apply(context,args); prev = now; } } }call、apply和bind
怎么去模擬一個(gè)call函數(shù)呢?
思路:call一個(gè)非常重要的作用就是改變上下文環(huán)境也就是this,我們可以給用戶傳入的上下文對(duì)象上添加一個(gè)函數(shù),通過(guò)這個(gè)上下文對(duì)象去執(zhí)行函數(shù),然后將這個(gè)函數(shù)刪除,返回結(jié)果就可以了。
Function.prototype.myCall = function(context, ...args) { context = context || window; // 給上下文對(duì)象上添加這個(gè)函數(shù) context.fn = this; // 通過(guò)這個(gè)上下文對(duì)象去執(zhí)行函數(shù) let result = context.fn(...args); // 將這個(gè)函數(shù)刪除 delete context.fn; return result; }
call既然都實(shí)現(xiàn)了,那么apply也是類似的,只不過(guò)傳入的參數(shù)是一個(gè)數(shù)組而已。
Function.prototype.myApply = function(context, arr) { context = context || window; arr = arr || []; let type = {}.toString.call(arr).slice(8,-1); if(type !== "Array") throw new TypeError("CreateListFromArrayLike called on non-object"); context.fn = this; let result = context.fn(...arr); delete context.fn; return result; }
模擬bind函數(shù),bind函數(shù)應(yīng)該返回一個(gè)新的函數(shù)。
Function.prototype.myBind = function(context, ...args) { // 保存當(dāng)前的函數(shù) let func = this; return function F(...params) { if(this instanceof F) { return new func(...args, ...params); } return func.apply(context,[...args,...params]); } }數(shù)組降維
function flattenDeep(arr) { if(!Array.isArray(arr)) return [arr]; return arr.reduce((prev,cur) => { return [...prev, ...flattenDeep(cur)]; },[]); } flattenDeep([1, [[2], [3, [4]], 5]]);棧的壓入和彈出
輸入兩個(gè)整數(shù)序列,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷第二個(gè)序列是否可能為該棧的彈出順序。假設(shè)壓入棧的所有數(shù)字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對(duì)應(yīng)的一個(gè)彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。
function IsPopOrder(pushV,popV){ if(pushV.length === 0) return false; var stack = []; // 模擬棧 for(var i = 0, j = 0; i < pushV.length;){ stack.push(pushV[i]); i += 1; // 壓入棧的值需要被彈出 while(j < popV.length && stack[stack.length-1] === popV[j]){ stack.pop(); j++; if(stack.length === 0) break; } } return stack.length === 0; }利用棧模擬隊(duì)列
思路:
對(duì)棧A添加數(shù)據(jù)。
如果棧B為空,循環(huán)將棧A中內(nèi)容彈出放入棧B,并彈出棧B最后一項(xiàng)
如果棧B不為空,則直接彈出棧B的最后一項(xiàng)
var stackA = []; var stackB = []; function push(node){ stackA.push(node); } function pop(){ if(!stackB.length){ while(stackA.length){ stackB.push(stackA.pop()); } } return stackB.pop(); }Fetch和ajax之間的區(qū)別
fetch
Fetch API是基于Promise設(shè)計(jì)的
容易同構(gòu)(前后端運(yùn)行同一套代碼)
語(yǔ)法簡(jiǎn)潔,更加語(yǔ)義化
原生支持率不高,可以用polyfill兼容IE8+瀏覽器
fetch(url).then(function(response){ return response.json(); }).then(function(data){ console.log(data); }).catch(function(err){ console.log(err); });
ajax
設(shè)計(jì)粗糙,不關(guān)注分離原則
基于事件的異步模型,不夠友好
var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "json"; xhr.onload = function(){ console.log(xhr.response); } xhr.onerror = function(){ console.log("error"); } xhr.send();Fetch常見(jiàn)坑
fetch請(qǐng)求默認(rèn)是不帶cookie的,需要設(shè)置 fetch(url, {credentials: "include"})
服務(wù)器返回400,500錯(cuò)誤碼時(shí)不會(huì)reject,只有網(wǎng)絡(luò)錯(cuò)誤導(dǎo)致不能完成時(shí),才會(huì)reject。
IE8, 9 的 XHR 不支持 CORS 跨域。
歸并排序將一個(gè)完整的數(shù)組分成兩部分,分別對(duì)其排序,然后將兩部分merge在一起即可。
function merge(left, right) { var temp = []; while(left.length && right.length) { if(left[0] < right[0]) temp.push(left.shift()); else temp.push(right.shift()); } return temp.concat(left,right); } function mergeSort(arr) { if(arr.length === 1) return arr; var mid = (arr.length/2)|0; var left = arr.slice(0,mid); var right = arr.slice(mid); return merge(mergeSort(left), mergeSort(right)); }箭頭函數(shù)的this原理
this 指向固定化,并不是因?yàn)榧^函數(shù)內(nèi)部有綁定 this 的機(jī)制,實(shí)際原因是箭頭函數(shù)沒(méi)有自己的 this ,導(dǎo)致內(nèi)部的this就是外層代碼的 this ,也正是因?yàn)闆](méi)有 this ,所以箭頭函數(shù)不能用作構(gòu)造函數(shù)。
js相關(guān)尺寸 BFC原理在BFC垂直方向元素邊距會(huì)發(fā)生重疊
不會(huì)與浮動(dòng)元素的box重合
獨(dú)立的容器,里外互不影響
浮動(dòng)元素參與計(jì)算
自定義事件var content = document.querySelector(".content"); // 自定義事件 var evt = new Event("custom"); var customEvt = new CustomEvent("customEvt", { // 通過(guò)這個(gè)屬性傳遞參數(shù) detail: { name: "tom", age: 12 } }); content.addEventListener("custom", (e) => { console.log("自定義事件被觸發(fā),無(wú)參數(shù)..."); console.log(e); }); content.addEventListener("customEvt", (e) => { console.log("自定義事件被觸發(fā),有參數(shù)..."); console.log(e); console.log(e.detail); }); // 點(diǎn)擊時(shí)觸發(fā)這個(gè)自定義事件 content.addEventListener("click", (e) => { content.dispatchEvent(evt); content.dispatchEvent(customEvt); });變量提升
var foo = 3; // 不在同一個(gè)作用域 function hoistVariable() { // 內(nèi)部變量提升導(dǎo)致 foo 的初始值為undefined // 所以 foo = 5; var foo = foo || 5; console.log(foo); // 5 } hoistVariable();
上邊的比較簡(jiǎn)單,看一個(gè)函數(shù)和變量同名,關(guān)于變量提升的小問(wèn)題。
var a = 6; function b(){ console.log(a); // @1 var a = 4; function a(){ alert(4); } console.log(a); //@2 } b();
因?yàn)镴avaScript中的函數(shù)是一等公民,函數(shù)聲明的優(yōu)先級(jí) 最高(高于變量提升),會(huì)被提升至當(dāng)前作用域最頂端,所以在 @1 輸出的是 function a(){alert(4);}
接下來(lái)執(zhí)行 a=4; 這一句,重新對(duì) a 進(jìn)行賦值。
函數(shù)已被提升,所以不考慮,所以在 @2 這里自然會(huì)輸出 4 。
如果還不能理解?且看預(yù)編譯后的代碼:
var a; a = 6; function b(){ var a; a = function a(){ // 函數(shù)先提升 alert(4); } console.log(a); // @1 a = 4; console.log(a); // @2 } b(); // 結(jié)果已經(jīng)非常明了了POST和GET的區(qū)別
POST對(duì)請(qǐng)求參數(shù)的長(zhǎng)度沒(méi)有限制,而GET如果請(qǐng)求參數(shù)過(guò)長(zhǎng),會(huì)被瀏覽器截?cái)唷?/p>
GET請(qǐng)求參數(shù)會(huì)直接暴露在URL上,所以不適合用來(lái)傳遞敏感信息。
GET請(qǐng)求可以被瀏覽器主動(dòng)緩存,而POST請(qǐng)求不可以,除非手動(dòng)設(shè)置。
GET請(qǐng)求在瀏覽器回退時(shí)是無(wú)害的,而POST會(huì)再次提交請(qǐng)求。
GET請(qǐng)求產(chǎn)生的URL可以被瀏覽器緩存,而POST不可以。
通信類1. 前后端如何通信?
ajax
WebSocket
CORS
2. 如何創(chuàng)建ajax?
// 創(chuàng)建xhr對(duì)象 var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP"); // GET 請(qǐng)求 xhr.open("GET",url,true); xhr.send(); // POST 請(qǐng)求 xhr.open("POST",url,true); // 表單數(shù)據(jù) , 也可以提交json數(shù)據(jù),相應(yīng)的content-Type: application/json xhr.setRequestHeader("content-Type", "application/x-www-from-urlencoded"); xhr.send(dataArr.join("&")); xhr.onload = function() { if(xhr.status === 200 || xhr.status === 304) { var data = xhr.responseText; // 拿到數(shù)據(jù) } else { // 出問(wèn)題了 } }
3. 跨域通信的幾種方式?
JSONP:利用 script 標(biāo)簽的跨域能力,服務(wù)返回一個(gè)js函數(shù)調(diào)用,數(shù)據(jù)作為函數(shù)的一個(gè)參數(shù)來(lái)傳遞。
var script = document.createElement("script"); script.type = "text/javascript"; script.src = url; // 跨域地址 document.head.appendChild(script); //有能耐把我這輩子都安排了,不然少他媽扯淡。 setTimeout(function() { document.head.removeChild(script); script = null; }); // 接收數(shù)據(jù) function jsonpCallback(data) { console.log(data); }
WebSocket:不受同源政策限制。
var ws = new WebSocket("wss://echo.websocket.org"); ws.onopen = function(e) { ws.send("hello..."); } ws.onmessage = function(e) { var data = e.data; } ws.onclose = function() { console.log("close..."); }
Hash:利用 location.hash 來(lái)傳值。 缺點(diǎn):數(shù)據(jù)直接暴露在url中,大小、類型都有限制。
1、父窗體可以把信息寫(xiě)在子窗體的href的hash上,子窗口通過(guò)監(jiān)聽(tīng)hashchange事件獲取信息。
2、子窗體改變父窗體的hash值,那么就要借助第三個(gè)子窗體,第三個(gè)子窗體是第二個(gè)子窗體的子窗體。(第三個(gè)子窗體要與父窗體同源)
3、第二個(gè)子窗體把信息設(shè)置在第三個(gè)子窗體的hash值上,然后第三個(gè)子窗體改變父窗體的hash值,從而實(shí)現(xiàn)跨域。
// 父窗體 var son = document.getElementByTagName("iframe"); son.src = son.src + "#" + data; // 子窗體 window.onhashchange = function() { var data = window.location.hash; }
postMessage :語(yǔ)法:window.postMessage(msg,targetOrigin)
// 窗口A 發(fā)送 BWindow.postMessage("發(fā)送的數(shù)據(jù)", "http://B.com"); // 窗口B 接收 window.addEventListener("message", (event) => { event.origin: // http://A.com event.source; // AWindow event.data; // "發(fā)送的數(shù)據(jù)" });
CORS: 跨域資源共享。
fetch(url, { method: "get", // 頭信息配置 }).then(() => {});安全類
CSRF,跨站請(qǐng)求偽造(Cross-site request forgery)
防御措施:
Token驗(yàn)證(請(qǐng)求必須攜帶Token)
Referer 驗(yàn)證(驗(yàn)證請(qǐng)求的來(lái)源是否可信)
XSS(cross-site scripting 跨站腳本攻擊)
原理:注入腳本
防御措施:對(duì)用戶的輸入做驗(yàn)證
渲染機(jī)制類1. 什么是DOCTYPE及作用?
用來(lái)聲明文檔類型和DTD規(guī)范的。
DTD(document type definition)文檔類型定義,是一系列的語(yǔ)法規(guī)則,用來(lái)聲明XML或(X)HTML的文件類型,瀏覽器會(huì)使用它來(lái)決定文檔類型,決定使用何種協(xié)議來(lái)解析,以及切換瀏覽器模式。
2. 常見(jiàn)的doctype有哪些?
HTML5
HTML4.01 Strict 嚴(yán)格模式 (不包含展示性或棄用的元素)
HTML4.01 Transitional 傳統(tǒng)(寬松)模式(包含展示性或棄用的元素)
頁(yè)面性能類提升頁(yè)面性能的方式?
資源壓縮合并,減少HTTP請(qǐng)求
非核心代碼異步加載
異步加載方式:
動(dòng)態(tài)腳本加載
defer (HTML解析完順序執(zhí)行)
async (加載完立即執(zhí)行)
利用瀏覽器緩存
使用CDN
預(yù)解析DNS
錯(cuò)誤監(jiān)控
前端錯(cuò)誤分類:代碼(運(yùn)行)錯(cuò)誤 資源加載錯(cuò)誤
錯(cuò)誤捕獲方式
運(yùn)行錯(cuò)誤捕獲:(1)try...catch (2)window.onerror
資源加載錯(cuò)誤 :(1)object.onerror(資源錯(cuò)誤不冒泡) (2)performance.getEntries() (3)Error事件捕獲(在事件流捕獲階段處理錯(cuò)誤)
跨域js運(yùn)行錯(cuò)誤也是可以捕獲的,捕獲的錯(cuò)誤:script error
上報(bào)錯(cuò)誤原理
利用Image對(duì)象上報(bào)
// 利用Image標(biāo)簽上報(bào)錯(cuò)(簡(jiǎn)單、不需要借助其他庫(kù)) (new Image()).src = "http://www.baidu.com/test?error=xxx";二分法查找
function binarySearch(arr,val,leftIndex,rightIndex) { if(leftIndex > rightIndex){ return; } var midIndex = (leftIndex + rightIndex) / 2 | 0; var midVal = arr[midIndex]; if(val > midVal) { return binarySearch(arr,val,midIndex+1,rightIndex); }else if(val < midVal) { return binarySearch(arr,val,leftIndex,midIndex-1); }else{ return midIndex; } }連續(xù)最長(zhǎng)不重復(fù)字符串
在一個(gè)字符串中找出連續(xù)的不重復(fù)的最大長(zhǎng)度的字符串,解決這類問(wèn)題的思路:
利用循環(huán)疊加字符串,直到出現(xiàn)重復(fù)為止
每一次疊加,記錄下來(lái)最大長(zhǎng)度的字符串
// 連續(xù)最長(zhǎng)不重復(fù)字符串 function getMaxLenStr(str) { var cur = []; var maxLenStr = ""; for(var i = 0; i < str.length; i++) { if(!cur.includes(str[i])) { cur.push(str[i]); } else { cur = []; // 置為空 cur.push(str[i]); } // 存儲(chǔ)最大長(zhǎng)度的字符串 if(maxLenStr.length < cur.length) { maxLenStr = cur.join(""); } } return maxLenStr; } getMaxLenStr("ababcabcde"); // abcde
和上面這道題有一樣思路的是:求一個(gè)數(shù)組當(dāng)中,連續(xù)子向量的最大和。
無(wú)非是將 對(duì)比字符串的長(zhǎng)度 改為 對(duì)比值大小
function FindGreatestSumOfSubArray(arr) { let sum = arr[0]; let max = arr[0]; for(let i = 1; i < arr.length; i++) { if(sum < 0) { sum = arr[i]; }else{ sum += arr[i]; } // 記錄最大值 if(max < sum) { max = sum; } } return max; }面試題:解碼字符串并輸出
阿里的一道面試題:給定一個(gè)編碼字符,按編碼規(guī)則進(jìn)行解碼,輸出字符串
編碼規(guī)則:coount[letter] ,將letter的內(nèi)容count次輸出,count是0或正整數(shù),letter是區(qū)分大小寫(xiě)的純字母。
實(shí)例:
const s= 3[a]2[bc]; decodeString(s); // 返回 ‘a(chǎn)aabcbc’
const s= 3[a2[c]]; decodeString(s); // 返回 ‘a(chǎn)ccaccacc’
const s= 2[ab]3[cd]ef; decodeString(s); // 返回 ‘a(chǎn)babcdcdcdef’
解題過(guò)程...
思路:
使用棧這種數(shù)據(jù)結(jié)構(gòu),如果push的內(nèi)容為‘]’,則循環(huán)pop字符,直到碰到’[‘,然后將pop
出來(lái)的字符串按規(guī)則整理后,重新push進(jìn)棧中,最后將棧內(nèi)的內(nèi)容拼接成字符串輸出即可。
代碼:
const s = "2[a2[c]]ef"; function decodeString(str) { let stack = []; // 存儲(chǔ)字符串的棧 for (let i = 0; i < str.length; i++) { let cur = str[i]; if (cur !== "]") { stack.push(cur); } else { // 彈出 let count = 0; let loopStr = []; let popStr = ""; while ((popStr = stack.pop()) !== "[") { loopStr.unshift(popStr); } count = stack.pop(); // 添加結(jié)果 let item = ""; for (let i = 0; i < count; i++) { item += loopStr.join(""); } stack.push(...(item.split(""))); } } return stack.join(""); } console.log(decodeString(s)); // accaccef排序算法時(shí)間復(fù)雜度
元素的移動(dòng)次數(shù)與關(guān)鍵字的初始排列次序無(wú)關(guān)的是:基數(shù)排列。
元素的比較次數(shù)與初始序列無(wú)關(guān)是:選擇排序。
算法的時(shí)間復(fù)雜度與初始序列無(wú)關(guān)的是:選擇排序。
BOM和DOMBOM 即瀏覽器對(duì)象模型,BOM沒(méi)有相關(guān)標(biāo)準(zhǔn),BOM的核心對(duì)象是window對(duì)象。
DOM即文檔對(duì)象模型,DOM是W3C標(biāo)準(zhǔn),DOM的最根本對(duì)象是document(window.document), 這個(gè)對(duì)象實(shí)際上是window對(duì)象的屬性,這個(gè)對(duì)象的獨(dú)特之處是唯一一個(gè)既屬于BOM有屬于DOM的對(duì)象。
http和WebSocket的區(qū)別:相同點(diǎn):
都是建立于tcp連接之上,通過(guò)tcp協(xié)議來(lái)傳輸數(shù)據(jù)。
不同點(diǎn):
HTTP是一種單向的協(xié)議,即客戶端只能向服務(wù)器端請(qǐng)求信息。request永遠(yuǎn)等于response,并且這個(gè)response是被動(dòng)的,不能主動(dòng)發(fā)起。一旦有一個(gè)任務(wù)超時(shí),就會(huì)阻塞后續(xù)的任務(wù)(線頭阻塞)。
HTTP協(xié)議是無(wú)狀態(tài)的,如使用輪詢、long poll都需要將身份鑒別信息上傳。
WebSocket真正的全雙工通信,只需要一次連接,這樣就避免了HTTP的無(wú)狀態(tài)性,服務(wù)器端可以主動(dòng)推送消息到達(dá)客戶端。
http2.0二進(jìn)制分幀
多路復(fù)用,這樣就避免了線頭阻塞
服務(wù)器端推送,客戶端請(qǐng)求HTML,服務(wù)器可以主動(dòng)推送js、css那些客戶端可能會(huì)用到的東西,這樣就避免了重復(fù)發(fā)送請(qǐng)求
頭壓縮
O(n)復(fù)雜度去重function unique(arr) { let obj = {}; let ret = []; for(let i = 0; i < arr.length; i++) { let cur = `${typeof arr[i]}-${arr[i]}`; if(!obj[cur]) { ret.push(arr[i]); obj[cur] = true; } } return ret; } var arr = [1, "1", 3, 3, 4]; unique(arr); // [1, "1", 3, 4]判斷是否相同
function isSame(a, b) { if(a === b) return true; if(typeof a !== typeof b) return false; // 如果均為object類型,判斷屬性個(gè)數(shù)是否相同 if(typeof a === "object" && typeof b === "object") { let aLen = Object.getOwnPropertyNames(a).length; let bLen = Object.getOwnPropertyNames(b).length; if(aLen !== bLen) return false; } return Object.getOwnPropertyNames(a).every(key => { if(typeof a[key] === "object") { return isSame(a[key], b[key]); } return a[key] === b[key]; }); }
后記一波:
付出了總歸是有回報(bào)的。
電話面試拿到了百度云事業(yè)部實(shí)習(xí)生的offer。
南京現(xiàn)場(chǎng)面試獲得了上海微盟的offer。
參加北京的面試得到了迅雷的offer。簽約那天剛好是中秋節(jié)(2018/9/24),可能是一份最棒的中秋大禮了吧
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97597.html
摘要:具體的時(shí)間線從月中旬,我開(kāi)始關(guān)注??途W(wǎng)的秋招內(nèi)推信息。直至十月中下旬結(jié)束秋招。之前也寫(xiě)過(guò)自己在廣州找實(shí)習(xí)的經(jīng)歷,那次把面試的過(guò)程都具體貼出來(lái)了。我今年就完美錯(cuò)過(guò)了春招實(shí)習(xí)經(jīng)歷。 前言 只有光頭才能變強(qiáng) 離上次發(fā)文章已經(jīng)快兩個(gè)月時(shí)間了,最近一直忙著秋招的事。今天是2018年10月22日,對(duì)于互聯(lián)網(wǎng)行業(yè)來(lái)說(shuō),秋招就基本結(jié)束了。我這邊的流程也走完了(不再筆試/面試了),所以來(lái)寫(xiě)寫(xiě)我的秋招經(jīng)歷...
摘要:適當(dāng)引導(dǎo)面試官。如果有機(jī)會(huì)來(lái)實(shí)習(xí),如何最有效的快速成長(zhǎng)淘寶技術(shù)部前端內(nèi)部有針對(duì)新同學(xué)的前端夜校,有專門的老師授課。 阿里巴巴2019前端實(shí)習(xí)生招聘還剩最后兩周,面向2019年11月1日至2020年10月31日之間畢業(yè)的同學(xué),在這里分享下阿里前端面試考核的關(guān)鍵點(diǎn): Q:在面試過(guò)程中,前端面試官如何考核面試者?A:會(huì)看同學(xué)為什么選擇前端行業(yè)?是因?yàn)樗惴ㄌy?Java、C++太難?還是因?yàn)闊?..
摘要:截至年月日零時(shí),杭州市常住人口為萬(wàn)人。年,杭州市實(shí)現(xiàn)地區(qū)生產(chǎn)總值億元。阿里巴巴對(duì)杭州的影響巨大,一線的七個(gè)企業(yè)中,有四個(gè)企業(yè)都是阿里巴巴大集團(tuán)下的。 歡迎持續(xù)關(guān)注我...
摘要:秋招變夏招,還沒(méi)準(zhǔn)備好團(tuán)隊(duì)成員收割機(jī)牽頭,帶領(lǐng)名成員歷時(shí)個(gè)月,整理了一份機(jī)器學(xué)習(xí)算法工程師求職面經(jīng)。但如果之前并沒(méi)有意識(shí)到這一問(wèn)題也沒(méi)關(guān)系,為你呈現(xiàn)一份小而美的面經(jīng)。這部分內(nèi)容包含了邏輯題目及概率題目?jī)煞矫娴膬?nèi)容。 秋招變夏招,還沒(méi)準(zhǔn)備好?Datawhale團(tuán)隊(duì)成員offer收割機(jī)牽頭,帶領(lǐng)14名成員歷時(shí)2個(gè)月,整理了一份機(jī)器學(xué)習(xí)算法工程師求職面經(jīng):Daily-interview。一份...
摘要:理論上來(lái)說(shuō),里是對(duì)象,給對(duì)象添加屬性是可以的。很明顯,這就是在或者函數(shù)上加了一個(gè)屬性,屬性值是函數(shù),作用是截取前后空格。要習(xí)慣的把中的一切看作對(duì)象,只要是對(duì)象,就是屬性的集合,屬性是鍵值對(duì)的形式。 今天在某個(gè)js交流群里看到這樣一個(gè)問(wèn)題: 親們,如果我定義一個(gè)function A() { } 可以給這個(gè)函數(shù)添加一個(gè)方法嗎?例如:A.use = function() { } ...
閱讀 3036·2021-11-18 10:07
閱讀 3785·2021-11-17 17:00
閱讀 2114·2021-11-15 18:01
閱讀 941·2021-10-11 10:58
閱讀 3399·2021-09-10 10:50
閱讀 3471·2021-08-13 15:05
閱讀 1240·2019-08-30 15:53
閱讀 2662·2019-08-29 13:01