摘要:快速排序由在年提出。如果定時器的時間到了,那么也會去下一個階段關(guān)閉的回調(diào)函數(shù),一些準備關(guān)閉的函數(shù)等的事件輪詢機制也可以看成是單線程,由上往下執(zhí)行,但是到了第階段,又會返回第一階段,死循環(huán)。
原生javaScript是中大公司挑人的核心,也是決定你未來發(fā)展高度的核心。
冒泡排序,快速排序,深度克隆,深度凍結(jié),數(shù)組操作,本章都有。
走遍大江南北,還是原生javaScript最美
感冒給大家更新,希望大家多多點贊,謝謝!
下面是本人一些其他文章和學(xué)習(xí)的文檔 , 全棧工程師一起加油!
Node.js之快速搭建微信公眾號服務(wù)器
Node.js之快速搭建服務(wù)器+前后端數(shù)據(jù)庫session交互
ES6教程全篇
你該擁抱的TypeScript
快速排序算法"這應(yīng)該是最簡單的快速排序?qū)崿F(xiàn),什么是快速排序呢?" "快速排序(Quicksort)是對冒泡排序的一種改進。 快速排序由C. A. R. Hoare在1962年提出。它的基本思想是: 通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨立的兩部分,其中一 部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再 按此方法對這兩部分數(shù)據(jù)分別進行快速排序,整個排序過程 可以遞歸進行,以此達到整個數(shù)據(jù)變成有序序列。" function quickSort(arr) { if (arr.length <= 1) { return arr; } var left = [], right = [], baseDot = Math.round(arr.length / 2) base = arr.splice(baseDot, 1)[0]; for (var i = 0; i < arr.length; i++) { if (arr[i] < base) { left.push(arr[i]) } else { right.push(arr[i]) } } return quickSort(left).concat([base], quickSort(right)); } let arr = [5, 3, 4, 12]; const newarr = quickSort(arr); console.log(newarr); "每次遞歸調(diào)用,都會直到數(shù)組中只有一個數(shù)字為止,然后 執(zhí)行上下文棧出棧,返回上一個執(zhí)行上下文循環(huán)遞歸,拼接數(shù)組"冒泡排序算法
"什么是冒泡排序算法?" "冒泡排序(Bubble Sort),是一種計算機科學(xué)領(lǐng)域的較簡單的排序算法。 它重復(fù)地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果他們的順 序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工作 是重復(fù)地進行直到?jīng)]有相鄰元素需要交換,也就是說該元素已經(jīng)排序完成。 這個算法的名字由來是因為越大的元素會經(jīng)由交換慢慢“浮”到數(shù)列的頂端 (升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端 一樣,故名“冒泡排序”。" bubbleSortSoul1 = (arr = []) => { let count = 0; // i為輪數(shù)(因i從0開始 即i深度克隆arr[j]? 如果有這種特殊癖好 那么j就從1開始吧,然后j arr[j + 1]) { let temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } console.log(`bubbleSortSoul1排序完成用了${count}輪`); return arr; }
"為什么我們需要深度克隆?而且面試必問?"
"因為引用數(shù)據(jù)類型存儲在堆空間中,當兩個變量同時指向同一個地址時, 只要一個改變,那么另外一個也會跟著變,我們的原意是想一個改變,另 一個不變,那么就需要重新開拓一個堆空間出來,所以就有了深度克隆。" "第一種方法(只適用于基礎(chǔ)類型)" const newObj = JSON.parse(JSON.stringify(oldObj)); "第二種方法,涵蓋所有的類型" const getType = (obj)=> { var toString = Object.prototype.toString; var map = { "[object Boolean]" : "boolean", "[object Number]" : "number", "[object String]" : "string", "[object Function]" : "function", "[object Array]" : "array", "[object Date]" : "date", "[object RegExp]" : "regExp", "[object Undefined]": "undefined", "[object Null]" : "null", "[object Object]" : "object", "[object Symbol]" : "symbol" }; if(obj instanceof Element) {//因為對不同標簽,toString會返回對應(yīng)不同標簽的構(gòu)造函數(shù) return "element"; } return map[toString.call(obj)]; } const getRegExp = re => { var flags = ""; if (re.global) flags += "g"; if (re.ignoreCase) flags += "i"; if (re.multiline) flags += "m"; return flags; }; /** * deep clone * @param {[type]} parent object 需要進行克隆的對象 * @return {[type]} 深克隆后的對象 */ const deepClone = oldObj => { // 維護兩個儲存循環(huán)引用的數(shù)組 const oldObjArr = []; const newObjArr = []; const clone = oldObj => { let newObj, proto; const type = getType(oldObj); switch(type){ case "boolean": case "number": case "string": case "null": case "undefined": case "function":{ return oldObj; break; } case "symbol":{ return Symbol(Symbol.keyFor(oldObj).toString()); break; } case "array":{ newObj = []; break; } case "regExp":{ newObj = new RegExp(oldObj.source, getRegExp(oldObj)); if (oldObj.lastIndex) newObj.lastIndex = oldObj.lastIndex; break; } case "date":{ newObj = new Date(oldObj.getTime()); break; } //case "obj": default:{ // 處理對象原型 proto = Object.getPrototypeOf(oldObj); // 利用Object.create切斷原型鏈 newObj = Object.create(proto); break; } } // 處理循環(huán)引用 const index = oldObjArr.indexOf(oldObj); if (index != -1) {// 如果父數(shù)組存在本對象,說明之前已經(jīng)被引用過,直接返回此對象 return newObjArr[index]; } oldObjArr.push(oldObj); newObjArr.push(newObj); /*數(shù)組和對象都可以用forin語句,雖然數(shù)組使用forin會有一個問題(具體看最下面)。 但是這里不會影響,所以這么用 */ for (let i in oldObj) {// 遞歸 newObj[i] = clone(oldObj[i]); } return newObj; }; return clone(oldObj); } /* 測試成功 */ function person(pname) { this.name = pname; } const Messi = new person("Messi"); function say() { console.log("hi"); }; const oldObj = { a: say, b: new Array(1), c: new RegExp("ab+c", "i"), d: Messi }; const newObj = deepClone(oldObj); console.log(newObj.a, oldObj.a); //[Function: say] [Function: say] console.log(newObj.b[0], oldObj.b[0]); // undefined undefined console.log(newObj.c, oldObj.c); // /ab+c/i /ab+c/i console.log(newObj.d.constructor, oldObj.d.constructor); // [Function: person][Function: person] "所有的類型都可以被克隆,完美版"
判斷對象是否一個數(shù)組的條件是:
Array.isArray(),這個在安卓的瀏覽器中兼容性一般
arr instanceof Array 這個兼容性不錯,可以使用
還有就是arr. _proto_ .consturctor == Array 這個也是可以的 兼容性應(yīng)該還不錯
Object.prototype.tostring.call(arr) == [object Array] 這個也可以
如何提取用最原生的方法提取一個對象內(nèi)部所有屬性的值,并且放在不同數(shù)組中?個人認為第一題和第二題結(jié)合起來,可以用來處理前后臺交互的數(shù)據(jù),如果格式很復(fù)雜,也可以使用這兩者的模式結(jié)合,然后把他們分別提取出來進行操作。
const obj = { name: "json", age: 1, friend: "夢露", info: { name: "Aron", age: 2, friend: "杰西卡", info: { name: "rose", age: 3, friend: "霉霉", info: { name: "jerry", age: 4, friend: "比伯", info: { name: "damu", age: 5, friend: "XJ", }, }, }, } } let namearr, agearr, friendarr; namearr = []; agearr = []; friendarr = []; check(obj); function check(obj) { const items = Object.getOwnPropertyNames(obj) items.forEach(function (item) { if (Object.prototype.toString.call(obj[item]) == "[object Object]") { check(obj[item]); } else { if (item.toString() === "name") { namearr.push(obj[item]) } else if (item.toString() === "age") { agearr.push(obj[item]) } else if (item.toString() === "friend") { friendarr.push(obj[item]) } } }) } /* 這種方法也是一樣的效果 使用for in循環(huán)代替的Object.getOwnPropertyNames(obj)方法 function check(obj) { for (var item in obj) { if (Object.prototype.toString.call(obj[item]) == "[object Object]") { check(obj[item]); } else { if (item == "name") { namearr.push(obj[item]) } else if (item == "age") { agearr.push(obj[item]) } else if (item == "friend") { friendarr.push(obj[item]) } } } }*/ console.log(`namearr:${namearr}`) console.log(`agearr:${agearr}`) console.log(`friendarr:${friendarr}`)請手寫一個數(shù)組由小到大排序而且去重,不得使用高階函數(shù)
let arr = [1, 1, 2, 2, 5, 5, "a", "a", "3", "3"] arr = arr.sort(); let realarr = []; for (let i = 0; i < arr.length; i++) { if (i == 0) { realarr.push(arr[i]) } else if (i !== 0 && arr[i] !== arr[i - 1]) { realarr.push(arr[i]) } } console.log(realarr)
### 如何將一個對象深度凍結(jié)?
跟上面的數(shù)組面試題一樣,利用了執(zhí)行上下文棧,先進的后出,最先凍結(jié)最深層里面的那個屬性, 再依次返回上一層繼續(xù)凍結(jié) var obj = { name:"王寶強", age:18, wife:{ name:"陳羽凡", age:17, son:{ name:"賈乃亮", age:48, girlFriend:{ name:"吳秀波", age:50, zuo:function () { console.log("翻舊賬") }, foods:["棉花糖","粉色的棉花糖","各種棉花糖",{a:"a"}] } } } }; Object.prototype.deepFreeze = function () { var keys = Object.getOwnPropertyNames(this); var that = this; keys.forEach(function (key) { var val = that[key]; if(Object.prototype.toString.call(val) === "[object Object]" || Object.prototype.toString.call(val) === "[object Array]"){ val.deepFreeze() } }); return Object.freeze(this) } obj.deepFreeze()
## 請使用定時器和canvas寫一個隨機生成多個彩色泡
請自己定義一個DOM節(jié)點的R操作,以此作為queryselector在IE8以下的polifill。Document
(function(w){ w.app = {}; w.app.getElementByClassName=function(className){ var allnode=document.getElementsByTagName("*"); console.log(allnode) var arr=[]; for(var i=0;i請你手寫一個ajax原生javaScript請求? "由于ajax一般用于比較舊的技術(shù),這里不適用ES6語法" var xhr = new XMLHttpRuest(); xhr.onreadystatechange = function () { if (xhr.readyState == 0) { //xhr對象創(chuàng)建好了 初始化狀態(tài) console.log(0) } if (xhr.readyState == 1) { //代表xhr.send方法還未調(diào)用(還未發(fā)送請求),還可以設(shè)置請求頭相關(guān)信息 console.log(1) } if (xhr.readyState == 2) { //此時send方法被調(diào)用了 響應(yīng)頭和首行已經(jīng)回來了 console.log(xhr.getResponseHeader("etag")) console.log(2) } if (xhr.readyState == 3) { console.log(3) } if (xhr.readyState === 4 && xhr.status === 200) { console.log(4) console.log(xhr.responseText); } } xhr.open("GET", "http://localhost:3000/ajax?username=123&password=456"); // xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); // xhr.send("username=123&password=456"); xhr.send() }*/ "http://上面是原生的ajax寫法,下面是jQuery中的兩種ajax寫法" " 1. 原生jQuery寫法 " $("#btn").click(function () { $.ajax({ url: "http://localhost:3000/ajax", data: "username=jack&password=123", method: "POST", success: function (data) { console.log(data) }, error: function (error) { console.log(error) } }) "2.簡寫" $.post("http://localhost:3000/ajax", "username=rose&age=12", (data) => { console.log(data) }) "http://如果是get請求直接上面改成get就可以了,data是服務(wù)器響應(yīng)回來的數(shù)據(jù)"然后這邊給一下服務(wù)器 Node.js的express代碼 響應(yīng)上面的ajax請求的const express = require("express"); const app = express(); app.use(express.static("public")) app.use(express.urlencoded({ extended: true })); app.get("/ajax", (req, res) => { console.log(req.query) res.send("這是ajax的get請求") }) app.post("/ajax", (req, res) => { res.send("這是ajax的post請求") console.log(req.body) }) app.listen(3000, err => { if (!err) { console.log("端口監(jiān)聽成功"); } else { console.log("端口監(jiān)聽失敗" + err); } })如何使用原生javaScript方法提取一個多重對象的值,并且塞到不同對應(yīng)的數(shù)組中?"這里使用了遞歸,還有Object原型上的方法,執(zhí)行上下文棧先進后出的知識。" const obj = { name: "json", age: 1, friend: "夢露", info: { name: "Aron", age: 2, friend: "杰西卡", info: { name: "rose", age: 3, friend: "霉霉", info: { name: "jerry", age: 4, friend: "比伯", info: { name: "damu", age: 5, friend: "XJ", }, }, }, } } let namearr, agearr, friendarr; namearr = []; agearr = []; friendarr = []; check(obj); /* function check(obj) { const items = Object.getOwnPropertyNames(obj) items.forEach(function (item) { if (Object.prototype.toString.call(obj[item]) == "[object Object]") { check(obj[item]); } else { if (item.toString() === "name") { namearr.push(obj[item]) } else if (item.toString() === "age") { agearr.push(obj[item]) } else if (item.toString() === "friend") { friendarr.push(obj[item]) } } }) }*/ function check(obj) { for (var item in obj) { if (Object.prototype.toString.call(obj[item]) == "[object Object]") { check(obj[item]); } else { if (item == "name") { namearr.push(obj[item]) } else if (item == "age") { agearr.push(obj[item]) } else if (item == "friend") { friendarr.push(obj[item]) } } } } console.log(`namearr:${namearr}`) console.log(`namearr:${agearr}`) console.log(`namearr:${friendarr}`)## 請手寫一個jsonp和cors 解決跨域問題的代碼 ?
"jsonp" document.getElementById("btn").onclick = function () { /* 1. jsonp - 特點: 1. 利用script標簽天然跨域跨域的特性解決跨域的, 民間推出的 2. 兼容性極好 */ //創(chuàng)建一個script標簽 const script = document.createElement("script"); //設(shè)置了響應(yīng)成功的回調(diào)函數(shù) window.jsoncallback = function (data) { console.log(data); } //設(shè)置script的src屬性, 向指定服務(wù)器發(fā)送請求 script.src = "http://localhost:3000/?callback=jsoncallback"; //添加到body中生效 document.body.appendChild(script); } ------ "cors的解決方法:在Node.js的服務(wù)器代碼中設(shè)置一個響應(yīng)頭" app.get("/cors", (req, res) => { /* 1. cors 特點: - 官方推出解決跨域的方案,使用起來及其簡單,只需在服務(wù)器設(shè)置一個響應(yīng)頭 - 兼容性較差 */ //設(shè)置響應(yīng)頭 res.set("access-control-allow-origin", "*"); //允許所有網(wǎng)址跨域瀏覽器的輪詢機制請簡述"1.瀏覽器的事件輪詢機制 瀏覽器中對于js依靠js引擎實現(xiàn),js引擎是單線程,不像java,php這些可以是多線程,高并發(fā)。如果要說到瀏覽器的輪詢機制,那么我們首先要說的 就是單線程的js引擎,前端的核心編程思維模式是異步編程,無論是頁面效果、前后端的數(shù)據(jù)交互,都是以異步為核心,每個需要異步的場景, 往往伴隨著回調(diào)函數(shù)去執(zhí)行,而單線程的JS引擎是無法自身做這么多工作,還需要異步線程。 1.每當JS引擎解析代碼時遇到異步代碼時,交給異步線程,繼續(xù)往下解析代碼。 2.異步線程處理這些異步代碼時,一旦他們的所對應(yīng)的回調(diào)函數(shù)達到執(zhí)行條件便會塞進異步隊列中,等待JS引擎的輪詢。 3.JS引擎會在解析完下面的所有代碼后,再去輪詢異步隊列,從左到右,依次執(zhí)行,這也是說為什么定時器的時間不準確的原因,在JS 解析代碼時,如果遇到下面代碼特別多的時候,那么它就沒時間去輪詢異步隊列的代碼。 瀏覽器中的輪詢機制有一個特殊的 requestAnimationFrame(callbackname),它所對應(yīng)的回調(diào)函數(shù),是在瀏覽器下一次重繪重排時執(zhí)行,它是一個宏任務(wù),有待考證 ,目前看只要觸發(fā)重繪重排就會調(diào)用回調(diào)函數(shù),可以避免掉幀,優(yōu)化性能,減少重繪重排次數(shù),即使一個空白頁面,它也會重繪重排,所以只要運用好, 它是完全可以替代定時器,還可以使用cancelAnimationFrame(callbackname)清除。 "Node.js中的事件輪詢機制 Event loop"Node.js的事件輪詢機制外還有同步代碼,微任務(wù), 要想徹底弄懂Node的代碼執(zhí)行,得結(jié)合下面的微任 務(wù)一起學(xué)習(xí)。" "1.執(zhí)行已經(jīng)到時間的setTimeout 和 setInterval 2.執(zhí)行延遲到一個循環(huán)迭代的i/o回調(diào) 3.系統(tǒng)內(nèi)部的 idle prepare等 4.poll 輪詢回調(diào)隊列,依次取出,同步執(zhí)行,與JS的異步隊列執(zhí)行有點相像 直到回調(diào)隊列為空 或者系統(tǒng)奔潰了 如果回調(diào)隊列沒有內(nèi)容,那么看 之前是否設(shè)置過setImmadiate(),如果有就去下一個階段,如果沒有,就在當前等待新的回調(diào)函數(shù)。 如果定時器的時間到了,那么也會去下一個階段 5. setImmediate 6.關(guān)閉的回調(diào)函數(shù) ,一些準備關(guān)閉的函數(shù)等. Node.js的事件輪詢機制也可以看成是單線程,由上往下執(zhí)行,但是到了第6階段,又會返回第一階段,死循環(huán)。 "什么是微任務(wù)什么是宏任務(wù)?"想得太多反而不好,把每個宏任務(wù)看成銀行排隊的老大爺,把微任務(wù)看成老大爺需要的業(yè)務(wù), 可能他需要辦存款,理財,買紀念幣等,柜臺人員不幫老大爺辦完 他所需要的任務(wù) -- 微任務(wù),就不會切換到下一個老大爺 -- 宏任務(wù), 但是編程的邏輯不 能完全抽象成現(xiàn)實生活, 照這種說法,只能先有老大爺才會有業(yè)務(wù)需要, ??墒窃贜ode中,先執(zhí)行的是微任務(wù),只有微任務(wù)如果有多層,先執(zhí)行最頂層,再往下依次執(zhí) 行)執(zhí)行完后才能去執(zhí)行宏任務(wù),微任務(wù)有兩種,一種是process.nextTick() 中的函數(shù),一種是Promise.then()中的函數(shù),只有他們執(zhí)行完后,才會去執(zhí)行宏任務(wù):setTim eout ,setIneterval,setImmadie。(即執(zhí)行完了微任務(wù)才會遵循Node.js的輪詢機制去執(zhí)行, 一切微任務(wù)優(yōu)先)"
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/53879.html
摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識,其實都是來自于實踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。 開篇 前端開發(fā)是一個非常特殊的行業(yè),它的歷史實際上不是很長,但是知識之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研...
摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識,其實都是來自于實踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。開篇 前端開發(fā)是一個非常特殊的行業(yè),它的歷史實際上不是很長,但是知識之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系...
摘要:我從沒有聽到有人問如何做一名優(yōu)秀甚至卓越的前端工程師。作為一個優(yōu)秀的前端工程師還需要深入了解以及學(xué)會處理的這些缺陷。再者,優(yōu)秀的前端工程師需要具備良好的溝通能力,因為前端工程師至少都要滿足四類客戶的需求。 我所遇到的前端程序員分兩種: 第一種一直在問:如何學(xué)習(xí)前端? 第二種總說:前端很簡單,就那么一點東西。 我從沒有聽到有人問:如何做一名優(yōu)秀、甚至卓越的WEB前端工程師...
摘要:我從沒有聽到有人問如何做一名優(yōu)秀甚至卓越的前端工程師。作為一個優(yōu)秀的前端工程師還需要深入了解以及學(xué)會處理的這些缺陷。再者,優(yōu)秀的前端工程師需要具備良好的溝通能力,因為前端工程師至少都要滿足四類客戶的需求。 我所遇到的前端程序員分兩種: 第一種一直在問:如何學(xué)習(xí)前端? 第二種總說:前端很簡單,就那么一點東西。 我從沒有聽到有人問:如何做一名優(yōu)秀、甚至卓越的WEB前端工程師...
摘要:我從沒有聽到有人問如何做一名優(yōu)秀甚至卓越的前端工程師。作為一個優(yōu)秀的前端工程師還需要深入了解以及學(xué)會處理的這些缺陷。再者,優(yōu)秀的前端工程師需要具備良好的溝通能力,因為前端工程師至少都要滿足四類客戶的需求。 我所遇到的前端程序員分兩種: 第一種一直在問:如何學(xué)習(xí)前端? 第二種總說:前端很簡單,就那么一點東西。 我從沒有聽到有人問:如何做一名優(yōu)秀、甚至卓越的WEB前端工程師...
閱讀 1621·2019-08-29 13:53
閱讀 3222·2019-08-29 13:50
閱讀 867·2019-08-27 10:51
閱讀 577·2019-08-26 18:36
閱讀 1827·2019-08-26 11:00
閱讀 619·2019-08-26 10:36
閱讀 3229·2019-08-23 17:58
閱讀 2039·2019-08-23 15:17