需求已改活已加,加班通宵看朝霞。 終是上線已延期,bug仍是改不完。javascript
面試造火箭,工做擰螺絲,雖然我只想擰螺絲,但是我須要用造火箭的技術去尋找擰螺絲的工做,如何能在面試過程當中讓本身處於不敗的地步呢,刷題是一個比較好的捷徑,今天就彙總了一些比較經典的面試題進行了彙總,分享給你們。前端
本文中的全部題目首發於公衆號【前端有的玩】,小編天天都會整理一道兩道面試題,而後推送給全部的朋友,關注小編,天天帶你去刷面試題,不想當鹹魚,想要換工做,還在猶豫什麼,關注 === 大廠offer。java
以下爲一段代碼,請完善sum函數,使得 sum(1,2,3,4,5,6) 函數返回值爲 21 ,須要在 sum 函數中調用 asyncAdd 函數進行數值運算,且不能修改asyncAdd函數面試
/** * 請在 sum函數中調用此函數,完成數值計算 * @param {*} a 要相加的第一個值 * @param {*} b 要相加的第二個值 * @param {*} callback 相加以後的回調函數 */
function asyncAdd(a,b,callback) {
setTimeout(function(){
callback(null, a+b)
},1000)
}
/** * 請在此方法中調用asyncAdd方法,完成數值計算 * @param {...any} rest 傳入的參數 */
async function sum(...rest) {
// 請在此處完善代碼
}
let start = window.performance.now()
sum(1, 2, 3, 4, 5, 6).then(res => {
// 請保證在調用sum方法以後,返回結果21
console.log(res)
console.log(`程序執行共耗時: ${window.performance.now() - start}`)
})
複製代碼
本題根據程序輸出時間不一樣,能夠劃分爲三個難度等級數組
async function sum(...rest) {
// 取出來第一個做爲初始值
let result = rest.shift()
// 經過for of 遍歷 rest, 依次相加
for(let num of rest) {
// 使用promise 獲取相加結果
result = await new Promise(resolve => {
asyncAdd(result, num, (_,res) => {
resolve(res)
})
})
}
// 返回執行結果
return result
}
// 執行成功,執行時長大於6秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`計算結果爲:${res}`)
})
複製代碼
在青銅難度,咱們把數組裏面的每一項依次相加。可是也能夠進行一些優化,能夠併發執行多個,好比 sum(1,2,3,4,5,6)
,能夠同時執行 1+2
,3+4
,5+6
,這樣就能夠提高執行效率promise
async function sum(...rest) {
// 若是傳的值少於2個,則直接返回
if (rest.length <= 1) {
return rest[0] || 0
}
const promises = []
// 遍歷將數組裏面的值兩個兩個的執行
for (let i = 0; i < rest.length; i += 2) {
promises.push(
new Promise(resolve => {
// 若是 rest[i+1] 是 undefined, 說明數組長度是奇數,這個是最後一個
if (rest[i + 1] === undefined) {
resolve(rest[i])
} else {
// 調用asyncAdd 進行計算
asyncAdd(rest[i], rest[i + 1], (_, result) => {
resolve(result)
})
}
})
)
}
// 獲取第一次計算結果
const result = await Promise.all(promises)
// 而後將第一次獲取到的結果即 [3,7,11] 再次調用 sum執行
return await sum(...result)
}
// 執行成功,執行時長大於3秒小於4秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`計算結果爲:${res}`)
})
複製代碼
async function sum(...rest) {
let result = 0
// 隱氏類型轉換, 對象 + 數字,會先調用對象的toString 方法
const obj = {}
obj.toString = function() {
return result
}
const promises = []
for(let num of rest) {
promises.push(new Promise((resolve) => {
asyncAdd(obj, num, (_, res) => {
resolve(res)
})
}).then(res => {
// 在這裏將 result的值改變以後,obj.toString 的返回值就變了,這時候下一個setTimeout調用時就使用了新值
result = res
}))
}
await Promise.all(promises)
return result
}
// 執行成功,執行時長大於1秒小於2秒
sum1(1, 2, 3, 4, 5,6).then(res => {
console.log(`計算結果爲:${res}`)
})
複製代碼
由於js
是執行在單線程裏面的,因此上面的代碼,咱們在for of
將全部的計算放到promises
數組裏面,而後經過Promise.all
去一次性執行,這時候並不須要考慮到底先執行哪兩個數字相加。由於單線程的緣由,咱們能夠保證這幾個Promise
是依次執行的,這時候obj.toString
返回值就是上一個Promise
的返回值,多跑幾遍代碼你就懂了哦markdown
請說明如下代碼各輸出了什麼?併發
console.log(typeof (() => {}))
console.log(typeof ['前端有的玩','公衆號'])
console.log(typeof null)
console.log(typeof undefined)
console.log(typeof Function.prototype)
console.log('子君' instanceof String)
console.log(new Date() instanceof Date)
複製代碼
// 輸出 function
console.log(typeof (() => {}))
// 輸出 object
console.log(typeof ['前端有的玩','公衆號'])
// 輸出 object
console.log(typeof null)
// 輸出 undefined
console.log(typeof undefined)
// 輸出 function
console.log(typeof Function.prototype)
// 輸出 false
console.log('子君' instanceof String)
// 輸出 true
console.log(new Date() instanceof Date)
複製代碼
須要注意的是,對於 typeof
, 能夠正確判斷除了null
以外的全部基本類型,而對於引用類型,除了函數外其餘都會被判斷爲object
。app
對於instanceof
,沒法判斷基本類型,但能夠正確判斷引用類型async
請實現一個instanceof
,讓如下代碼可正常運行
/** 自定義instanceof */
function instanceOf(left, right) {
// 請完善如下代碼,不能使用原生instanceof
}
class A{}
class B extends A {}
class C{}
const b = new B()
// 輸出 true
console.log(instanceOf(b,B))
// 輸出 true
console.log(instanceOf(b,A))
// 輸出 false
console.log(instanceOf(b,C))
複製代碼
本題主要考察instanceof
的判斷原理,instanceof
主要的實現原理就是隻要右邊變量的 prototype
在左邊變量的原型鏈上便可。所以,instanceof
在查找的過程當中會遍歷左邊變量的原型鏈,直到找到右邊變量的 prototype
,若是查找失敗,則會返回 false
。
/** 自定義instanceof */
function instanceOf(left, right) {
let proto = left.__proto__
while(proto){
if(proto === right.prototype){
return true
}
proto = proto.__proto__
}
return false
}
class A{}
class B extends A {}
class C{}
const b = new B()
// 輸出 true
console.log(instanceOf(b,B))
// 輸出 true
console.log(instanceOf(b,A))
// 輸出 false
console.log(instanceOf(b,C))
複製代碼
請模擬實現new
操做符,使下面代碼正常運行
function myNew(constructor, ...rest) {
// 請在此處完善代碼,不能直接使用 new 操做符
}
function Fun(name,sex) {
this.name = name
this.sex = sex
}
Fun.prototype.getUserInfo = function() {
return `個人姓名${this.name},個人性別${this.sex}`
}
const fun = myNew(Fun,'子君','男')
// 個人姓名子君,個人性別男
console.log(fun.getUserInfo())
複製代碼
這道題考察的是使用new操做符
調用構造函數所經歷的階段:
function myNew(constructor, ...rest) {
if (typeof constructor !== 'function') {
return constructor;
}
//建立新的對象,關聯構造函數的原型對象
const _constructor = Object.create(constructor.prototype);
//執行構造函數
const obj = constructor.apply(_constructor, rest);
//若是構造函數執行結果是對象則返回執行結果
if (typeof obj === 'object') {
return obj;
} else {
return _constructor;
}
}
function Fun(name,sex) {
this.name = name
this.sex = sex
}
Fun.prototype.getUserInfo = function() {
return `個人姓名${this.name},個人性別${this.sex}`
}
const fun = myNew(Fun,'子君','男')
// 個人姓名子君,個人性別男
console.log(fun.getUserInfo())
複製代碼
請說出如下代碼輸出內容
const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'
// 我是子君仍是君子呢
console.log(a[b])
const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'
// 我是子君仍是君子呢
console.log(d[e])
複製代碼
const a = {}
const b = Symbol('1')
const c = Symbol('1')
a[b] = '子君'
a[c] = '君子'
// 輸出子君
console.log(a[b])
const d = {}
const e = {key: '1'}
const f = {key: '2'}
d[e] = '子君'
d[f] = '君子'
// 輸出君子
console.log(d[e])
複製代碼
對於第一個輸出,Symbol()
函數會返回**「symbol」**類型的值,而Symbol
函數傳的參數僅僅是用於標識的,不會影響值的惟一性
對於第二個輸出, 由於e
和f
都是對象,而對象的key
只能是數值或字符,因此會將對象轉換爲字符,對象的toString
方法返回的是[object Object]
, 全部輸出的是君子
請說出如下代碼輸出的內容
console.log([] + [])
console.log({} + [])
console.log([] == ![])
console.log(true + false)
複製代碼
// 輸出 "" 空字符串
console.log([] + [])
複製代碼
這行代碼輸出的是空字符串""
, 包裝類型在運算的時候,會先調用valueOf
方法,若是valueOf
返回的仍是包裝類型,那麼再調用toString
方法
// 仍是 數組
const val = [].valueOf()
// 數組 toString 默認會將數組各項使用逗號 "," 隔開, 好比 [1,2,3].toSting 變成了"1,2,3",空數組 toString 就是空字符串
const val1 = val.toString() // val1 是空字符串
複製代碼
因此上面的代碼至關於
console.log("" + "")
複製代碼
第二行代碼
// 輸出 "[object Object]"
console.log({} + [])
複製代碼
和第一題道理同樣,對象 {}
隱氏轉換成了[object Object]
,而後與""
相加
第三行代碼
// 輸出 true
console.log([] == ![])
複製代碼
對於===
, 會嚴格比較二者的值,可是對於==
就不同了
因此對於上面的代碼,看下面一步一步分析
// 這個輸出 false
console.log(![])
// 套用上面第三條 將 false 轉換爲 數值
// 這個輸出 0
console.log(Number(false))
// 包裝類型與 基本類型 == 先將包裝類型經過 valueOf toString 轉換爲基本類型
// 輸出 ""
console.log([].toString())
// 套用第2條, 將空字符串轉換爲數值、
// 輸出 0
console.log(Number(""))
// 因此
console.log(0 == 0)
複製代碼
null == undefined
number
與number
比較,會將其轉換爲number
boolean
,那麼會先將boolean
轉換爲number
第四行代碼
// 輸出 1
console.log(true + false)
複製代碼
兩個基本類型相加,若是其中一方是字符,則將其餘的轉換爲字符相加,不然將類型轉換爲Number
,而後相加, Number(true)
是1
, Number(false)
是0
, 因此結果是 1
本文中的全部題目首發於公衆號【前端有的玩】,小編天天都會整理一道兩道面試題,而後推送給全部的朋友,關注小編,天天帶你去刷面試題,不想當鹹魚,想要換工做,還在猶豫什麼,關注 === 大廠offer。
不要吹滅你的靈感和你的想象力; 不要成爲你的模型的奴隸。 ——文森特・梵高