寫給自己看的面試題整理-演算法&某東筆試題
-
排序(背誦氣泡排序、選擇排序、計數排序、快速排序、插入排序、歸併排序)
- js Array.prototype.sort 方法瞭解一下?
const swap(arr, a, b) { // a, b 是下標 let t = arr[a] arr[a] = arr[b] arr[b] = t } 複製程式碼
const arr = [8, 100, 50, 22, 15, 6, 1, 1000, 999, 0] window.Array.prototype.sort.call(arr, function(a, b) { return a - b }) arr 複製程式碼
- 冒泡
const arr = [8, 100, 50, 22, 15, 6, 1, 1000, 999, 0] const bubleSort = function(arr) { for(let j = arr.length; j > 1; j--) { for(let i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i+1]) { let t = arr[i] arr[i] = arr[i+1] arr[i+1] = t } } } return arr } const x = bubleSort(arr) x 複製程式碼
- 選擇
const arr = [8, 100, 50, 22, 15, 6, 1, 1000, 999, 0] const selectSort = function() { let index for(let i = 0; i < arr.length; i++) { index = i for(let j = i + 1; j < arr.length; j++) { if(arr[index] > arr[j]) { index = j } } if(index !== i) { let t = arr[i] arr[i] = arr[index] arr[index] = t } } return arr } const x = selectSort(arr) x 複製程式碼
- 計數
// 有一定的侷限 只能用於整數 const counterSort = function() { } 複製程式碼
-
快速
const arr = [6, 1, 2, 7, 9, 3, 4, 5, 10, 8] const quickSort(arr) { if(arr.length <= 1) { return arr } let midPos = Math.floor(arr.length / 2) // 呼叫了 js 原生 api 懶得寫了 大體就是用 二分的思想吧--。 } 複製程式碼
-
插入
// 從後往前比較 知道碰到比當前項還要小的前一項時 將這一項插入到前一項的後面 複製程式碼
- 歸併
-
二分查詢法
-
翻轉二叉樹
第三個二叉樹暫時先放棄了....
京東筆試題:
-
手寫 Ajax 工具類,例如 request(url, option)
const request = function(url, option) { let xhr = new XMLHttpRequest() xhr.open(option, url) xhr.onreadystatechange = function() { if(xhr.readyState === 4 && xhr.status === 200) { // responseCallback() console.log(xhr.responseText) } } } 複製程式碼
-
跨域有哪些解決方案。 說說JSONP的實現。
function jsonp(setting) { settings.data = settings.data || {} settings.key = settings.key || 'callback' settings.callback = settings.callback || function() {} settings.data[settings.key] = '__onGetData__' window.__onGetData__ = function(data) { settings.callback(data) } let script = document.createElement('script') let query = [] for(let key in settings.data) { query.push(key + '=' + encodeURIComponent(settings.data[key])) } script.src = settings.url + '?' + query.join('&') document.head.appendChild(script) document.head.removeChild(script) } jsonp({ url: 'http://photo.sina.cn/aj/index', key: 'jsoncallback', data: { page: 1, cate: 'recommend', }, callback: function(ret) { console.log(ret) } }) 複製程式碼
-
CORS-跨域資源訪問
-
-
js有哪些實現繼承的方式。 閉包是什麼?
- class extends
- 閉包
- 第一種說法 閉包可以用來間接訪問一個變數,閉包可以用來隱藏一個變數
- 第二種說法: 閉包返回一個函式,這個函式可以操作其他函式內部的變數
function getAdder() { let n = 0 return function() { n++ console.log('n: ', n) } } let adder = getAdder() adder() adder() 複製程式碼
-
寫一個函式把手機號格式化: 13499991212 => 134 9999 1212
-
寫出一下程式碼的輸出結果
let leng = 1 function fn() { console.log(this.leng) } let obj = { leng: 2, method1: function(fn) { fn() // undefined fn.call(this) // 2 arguments[0]() // undefined }, method2: function() { document.addEventListener('click', evt => this.method3(evt.type), false) }, method3: function(type) { console.log(type + ' : ' + this.leng ) // 'click: 2' }, } obj.method1(fn) obj.method2(fn) // 點選頁面之後列印什麼? 複製程式碼
-
寫出下面程式碼的輸出結果
let reg = /abc/g let str = 'abcd' reg.test(str) // true reg.test(str) // false 複製程式碼
-
寫出一個複製物件的方法 包括淺複製 和 深複製
// 淺 let person = { age: 18, name: 'guakun', hobby: { first: 'code', second: 'code', } } let person2 = {} for(key in person) { person2[key] = person[key] } 複製程式碼
-
寫出下面程式碼的輸出結果
console.log(1) setTimeout(function() { console.log(2) }, 0) console.log(3) 複製程式碼
-
寫出下面程式碼的輸出結果
let p1 = {name: 'john', age: 30} let p2 = {name: 'lucy', age: 20} function modify1(obj) { p1 = {name: 'backus'} } function modify2(obj) { obj.name = 'guakun' } modify1(p1) modify2(p2) console.log(p1) // {name: 'backus'} console.log(p2) // {name: 'guakun', age: 20} 複製程式碼
-
如何實現以下效果
function add(num1) { return function(num2) { console.log(num1+num2) } } add(2)(5) 複製程式碼
-
解釋一下變數提升(hoisting)
-
事件物件的 target 和 currentTarget 屬性有什麼區別
- event.target 返回的是觸發事件的元素
- event.currentTarget 返回的是繫結事件的元素
-
DOM 事件流是什麼,各瀏覽器的相容性
捕獲和冒泡 相容性的問題我不會
-
load 和 DOM ready 有什麼區別?
-
寫一個找出陣列中重複元素的函式, 例如[0, 1, 2, 3, 4, 1, 4] 返回[1, 4]
//計數排序 let a = [0, 1, 2, 3, 4, 1, 4] let hashTab = {} let repeateHashTab = {} for(let index = 0; index < a.length; index++) { if(!(a[index] in hashTab)){ hashTab[a[index]] = true } else { repeateHashTab[a[index]] = true } } console.log(Object.keys(repeateHashTab)) function getInt(arr) { let newArr = [] newArr = arr.map((item) => item-0) return newArr } console.log(getInt(Object.keys(hashTab))) 複製程式碼
-
如何提高滾動事件的效能
-
防抖
防抖技術即是可以把多個順序地呼叫合併成一次,也就是在一定時間內,規定事件被觸發的次數。
// 防抖動函式 function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate & !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; var myEfficientFn = debounce(function() { // 滾動中的真正的操作 }, 250); // 繫結監聽 window.addEventListener('resize', myEfficientFn); 複製程式碼
-
節流
防抖函式確實不錯,但是也存在問題,譬如圖片的懶載入,我們希望在下滑過程中圖片不斷的被載入出來,而不是隻有當停止下滑時候,圖片才被載入出來。 這個時候,我們希望即使頁面在不斷被滾動,但是滾動 handler 也可以以一定的頻率被觸發(譬如 250ms 觸發一次),這類場景,就要用到另一種技巧,稱為節流函式(throttling)。 節流函式:只允許一個函式在 X 毫秒內執行一次。 與防抖相比,節流函式最主要的不同在於它保證在 X 毫秒內至少執行一次我們希望觸發的事件 handler。 同樣是利用定時器,看看簡單的示例
// 簡單的節流函式 function throttle(func, wait, mustRun) { var timeout, startTime = new Date(); return function() { var context = this, args = arguments, curTime = new Date(); clearTimeout(timeout); // 如果達到了規定的觸發時間間隔,觸發 handler if(curTime - startTime >= mustRun){ func.apply(context,args); startTime = curTime; // 沒達到觸發間隔,重新設定定時器 }else{ timeout = setTimeout(func, wait); } }; }; // 實際想繫結在 scroll 事件上的 handler function realFunc(){ console.log("Success"); } // 採用了節流函式 window.addEventListener('scroll',throttle(realFunc,500,1000)); 複製程式碼
-
-
談下對 Promise 的理解
一種優雅的非同步解決方案 // q function Promise() { return } let promise = new Promise(function(x, y) { setTimeout(()=>{ x(101) }, 3000) }) promise.then((z) => { console.log(z) }) // a function Promise(fn) { let status = 'pending' function successNotify() { status = 'resolved' toDoThen() } function failNotify() { status = 'rejected' toDoThen() } function toDoThen() { if(status === 'resolved') { for(let i=0; i< successArray.length; i++) { successArray[i].call() } } else if(status === 'rejected') { for(let i=0; i<failArray.length; i++) { failArray[i].call() } } } let successArray = [] let failArray = [] fn.call(undefined, successNotify, failNotify) return { then: function(successFn, failFn) { successArray.push(successFn) failArray.push(failFn) return undefined // 簡化 } } } 複製程式碼
-
寫出下面程式碼的輸出結果(es6)
let x = 3 function fn (y = x) { let x = 4 console.log(y) } fn() // out: 3 複製程式碼