面試造火箭,看下這些大廠原題

需求已改活已加,加班通宵看朝霞。 終是上線已延期,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}`)
})
複製代碼

本題根據程序輸出時間不一樣,能夠劃分爲三個難度等級數組

  1. 青銅難度, 輸出時長大於6秒
  2. 白銀難度, 輸出時長大於3秒
  3. 王者難度, 輸出時長大於1秒

答案

  1. 青銅難度
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}`)
})

複製代碼
  1. 白銀難度

在青銅難度,咱們把數組裏面的每一項依次相加。可是也能夠進行一些優化,能夠併發執行多個,好比 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}`)
})
複製代碼
  1. 王者難度
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以外的全部基本類型,而對於引用類型,除了函數外其餘都會被判斷爲objectapp

對於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操做符調用構造函數所經歷的階段:

  1. 建立一個新的對象;
  2. 將構造函數的做用域賦給新的對象;
  3. 執行構造函數中的代碼;
  4. 返回新的對象;
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函數傳的參數僅僅是用於標識的,不會影響值的惟一性

對於第二個輸出, 由於ef都是對象,而對象的key只能是數值或字符,因此會將對象轉換爲字符,對象的toString方法返回的是[object Object], 全部輸出的是君子

題目六

題目介紹

請說出如下代碼輸出的內容

console.log([] + [])
console.log({} + [])
console.log([] == ![])
console.log(true + false)
複製代碼

答案

  1. 第一行代碼
// 輸出 "" 空字符串
console.log([] + [])
複製代碼

這行代碼輸出的是空字符串"", 包裝類型在運算的時候,會先調用valueOf方法,若是valueOf返回的仍是包裝類型,那麼再調用toString方法

// 仍是 數組
const val = [].valueOf()
// 數組 toString 默認會將數組各項使用逗號 "," 隔開, 好比 [1,2,3].toSting 變成了"1,2,3",空數組 toString 就是空字符串
const val1 = val.toString() // val1 是空字符串
複製代碼

因此上面的代碼至關於

console.log("" + "")
複製代碼
  1. 第二行代碼

    // 輸出 "[object Object]"
    console.log({} + [])
    複製代碼

    和第一題道理同樣,對象 {}隱氏轉換成了[object Object],而後與""相加

  2. 第三行代碼

    // 輸出 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)
    複製代碼
    1. 好比 null == undefined
    2. 若是非numbernumber比較,會將其轉換爲number
    3. 若是比較的雙方中由一方是boolean,那麼會先將boolean轉換爲number
  3. 第四行代碼

    // 輸出 1
    console.log(true + false)
    複製代碼

    兩個基本類型相加,若是其中一方是字符,則將其餘的轉換爲字符相加,不然將類型轉換爲Number,而後相加, Number(true)1, Number(false)0, 因此結果是 1

本文中的全部題目首發於公衆號【前端有的玩】,小編天天都會整理一道兩道面試題,而後推送給全部的朋友,關注小編,天天帶你去刷面試題,不想當鹹魚,想要換工做,還在猶豫什麼,關注 === 大廠offer。

結語

不要吹滅你的靈感和你的想象力; 不要成爲你的模型的奴隸。 ——文森特・梵高

相關文章
相關標籤/搜索