典型的JavaScript面試題(附答案)

原文:https://dev.to/maxpou/typical-javascript-interview-exercises-explained

題目一

下面的代碼,我想要打印出hey amy,結(jié)果卻打印出hey arnold,為什么?

function greet (person) {
  if (person == { name: 'amy' }) {
    return 'hey amy'
  } else {
    return 'hey arnold'
  }
}
greet({ name: 'amy' })
答案

這里問(wèn)題出在{ name: 'amy' } != { name: 'amy' }。當(dāng)比較兩個(gè)對(duì)象時(shí),JavaScript都會(huì)比較對(duì)象在內(nèi)存中的引用地址粘衬。這個(gè)例子中,兩個(gè)對(duì)象雖然都有相同的屬性和值咳促,但它們?cè)趦?nèi)存中地址是不同的稚新,所以是兩個(gè)不同的對(duì)象。

正確的解決方法應(yīng)該是比較對(duì)象屬性的值:

function greet (person) {
  if (person.name === 'amy') {
    return 'hey amy'
  }
  return 'hey arnold'
}
greet({ name: 'amy' }) // "hey amy"

題目二

我想讓下面的代碼按順序輸出0跪腹,1褂删,2,3冲茸,但是運(yùn)行結(jié)果卻不符合我的預(yù)期屯阀,為什么以及怎么解決?

for (var i = 0; i < 4; i++) {
  setTimeout(() => console.log(i), 0)
}
問(wèn)題

我喜歡這道題轴术,因?yàn)樗悬c(diǎn)棘手难衰,并且它涉及到作用域和JavaScript的事件循環(huán)。

這里的陷阱是零延遲逗栽。setTimeout(callback, 0)并不意味著callback函數(shù)會(huì)在0毫秒后執(zhí)行盖袭。

下面是事件循環(huán)的經(jīng)過(guò):

  1. 當(dāng)前調(diào)用棧設(shè)為第一個(gè)setTimeout()
  2. window.setTimeout()是一個(gè)web api,在經(jīng)過(guò)0毫秒后彼宠,回調(diào)函數(shù)(在這里是匿名函數(shù))會(huì)被放到隊(duì)列中鳄虱,而不是調(diào)用棧中。
  3. 當(dāng)調(diào)用椘鞠浚空閑時(shí)拙已,for循環(huán)會(huì)將第二個(gè)setTimeout放進(jìn)來(lái),然后將第二個(gè)callback放到隊(duì)列中摧冀。咪奖。。直到循環(huán)結(jié)束钥勋。
  4. 當(dāng)for循環(huán)結(jié)束i === 4時(shí),JS就會(huì)執(zhí)行隊(duì)列里的callback函數(shù)了。每一個(gè)console.log(i)會(huì)將i打印出來(lái)楼镐,也就是4癞志。

用動(dòng)畫(huà)演示整個(gè)事件循環(huán)的過(guò)程:Loupe (try it it's fun!)

還有一個(gè)問(wèn)題是變量i的作用域的問(wèn)題,我們可以看到4個(gè)setTimeout函數(shù)都共享著同一個(gè)i = 4(并不是第一個(gè)setTimeout的i = 0框产,第二個(gè)i = 1等等)

答案

針對(duì)以上問(wèn)題我們有不同的解決方案:

  • 使用立即自執(zhí)行函數(shù)(IIFE)凄杯,這種“包裹”函數(shù)會(huì)在它被定義時(shí)立即執(zhí)行:
for (let i = 0; i < 4; i++) {
  (function (i) {
    setTimeout(() => console.log(i), 0)
  })(i)
}
  • 用let代替var。let作用于塊作用域秉宿,能讓作用域更容易理解戒突。
for (let i = 0; i < 4; i++) {
  setTimeout(() => console.log(i), 0)
}

題目三

我想讓下面的代碼輸出doggo,但結(jié)果卻輸出undefined!

let dog = {
  name: 'doggo',
  sayName () {
    console.log(this.name)
  }
}
let sayName = dog.sayName
sayName()
答案

上面的代碼執(zhí)行返回undefined描睦,為什么呢膊存?首先,我們定義了一個(gè)對(duì)象名叫dog忱叭,這個(gè)對(duì)象有兩個(gè)屬性隔崎,分別是name和sayName方法。然后我們?cè)俣x了一個(gè)變量叫做sayName韵丑,并將dog對(duì)象的sayName方法賦值給它爵卒。最后在當(dāng)前環(huán)境也即是全局環(huán)境執(zhí)行sayName方法,這時(shí)函數(shù)里的this指向的是window撵彻,而window對(duì)象下面并沒(méi)有name屬性钓株,所以返回undefined.

  • 如果我們要訪問(wèn)dog對(duì)象的name屬性,我們就要將sayName的執(zhí)行環(huán)境變成dog:
sayName.bind(dog)()
// 或者:
dog.sayName.bind(dog)()
  • 直接在dog對(duì)象上調(diào)用sayName方法:
let dog = {
  name: 'doggo',
  sayName () {
    console.log(this.name)
  }
}
dog.sayName() // will log "doggo"

題目四

我想執(zhí)行bark方法陌僵,但卻報(bào)錯(cuò)了轴合,為什么?

function Dog (name) {
  this.name = name
}
Dog.bark = function () {
  console.log(this.name + ' says woof')
}
let fido = new Dog('fido')
fido.bark()
答案

執(zhí)行上面代碼碗短,我們會(huì)得到如下錯(cuò)誤:TypeError: fido.bark is not a function. 上面的代碼我們給函數(shù)Dog(同時(shí)也是構(gòu)造器)增加一個(gè)bark方法值桩。這在JavaScript中是可以的,因?yàn)楹瘮?shù)也是對(duì)象豪椿。(譯者補(bǔ)充:bark是Dog的靜態(tài)方法奔坟,fido是Dog的實(shí)例對(duì)象,實(shí)例對(duì)象無(wú)法訪問(wèn)構(gòu)造器的靜態(tài)方法)搭盾。

  • 雖然fido.bark不是一個(gè)方法咳秉,但Dog.bark是,所以我們可以用之前的方法來(lái)處理鸯隅,就是用function.prototype.bind來(lái)改變this的指向:
var boundedBark = Dog.bark.bind(fido)
boundedBark() // "fido says woof"
  • 將bark方法放在Dog的原型上:
function Dog (name) {
  this.name = name
}

Dog.prototype.bark = function () {
  console.log(this.name + ' says woof')
}

let fido = new Dog('fido')
fido.bark() // "fido says woof"

我們還可以使用ES2015中的class關(guān)鍵字澜建,但其實(shí)它是上面代碼的語(yǔ)法糖向挖。

class Dog {
  constructor (name) {
    this.name = name
  }

  bark () {
    console.log(this.name + ' says woof')
  }
}

let fido = new Dog('fido')
fido.bark() // "fido says woof"

題目五

為什么下面代碼執(zhí)行的結(jié)果是這樣的?

function isBig (thing) {
  if (thing == 0 || thing == 1 || thing == 2) {
    return false
  }
  return true
}
isBig(1)    // false
isBig([2])  // false
isBig([3])  // true
答案

因?yàn)槲覀冊(cè)谶@里使用了==而不是嚴(yán)格相等===炕舵,也就是不進(jìn)行類型的比較:

  • 調(diào)用isBig(1)何之,這時(shí)thing == 1,結(jié)果符合我們的預(yù)期咽筋,返回false溶推。
  • 調(diào)用isBig([2]),thing == [2]奸攻,這時(shí)發(fā)生了什么呢蒜危?當(dāng)比較一個(gè)數(shù)組和數(shù)字時(shí),數(shù)組會(huì)轉(zhuǎn)化成數(shù)字睹耐。這是Abstract Equality Comparison Algorithm的一部分辐赞,所以[2] == 2。

我們應(yīng)該避免使用==

// weird results
[] == ![]     // true
[] == false   // true

// Non transitive relation
"1" == true   // true
"01" == true  // true
"01" == "1"   // false

題目六(彩蛋無(wú)答案)

如何讓heroes數(shù)組不可變硝训?

const heroes = [
  { name: 'Wolverine',      family: 'Marvel',    isEvil: false },
  { name: 'Deadpool',       family: 'Marvel',    isEvil: false },
  { name: 'Magneto',        family: 'Marvel',    isEvil: true  },
  { name: 'Charles Xavier', family: 'Marvel',    isEvil: false },
  { name: 'Batman',         family: 'DC Comics', isEvil: false },
  { name: 'Harley Quinn',   family: 'DC Comics', isEvil: true  },
  { name: 'Legolas',        family: 'Tolkien',   isEvil: false },
  { name: 'Gandalf',        family: 'Tolkien',   isEvil: false },
  { name: 'Saruman',        family: 'Tolkien',   isEvil: true  }
]

const newHeroes = heroes.map(h => {
  h.name = h.name.toUpperCase()
  return h
})

你的答案是什么响委?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窖梁,隨后出現(xiàn)的幾起案子晃酒,更是在濱河造成了極大的恐慌,老刑警劉巖窄绒,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贝次,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡彰导,警方通過(guò)查閱死者的電腦和手機(jī)蛔翅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)位谋,“玉大人山析,你說(shuō)我怎么就攤上這事√透福” “怎么了笋轨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赊淑。 經(jīng)常有香客問(wèn)我爵政,道長(zhǎng),這世上最難降的妖魔是什么陶缺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任钾挟,我火速辦了婚禮,結(jié)果婚禮上饱岸,老公的妹妹穿的比我還像新娘掺出。我一直安慰自己徽千,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布汤锨。 她就那樣靜靜地躺著双抽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闲礼。 梳的紋絲不亂的頭發(fā)上牍汹,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音位仁,去河邊找鬼。 笑死方椎,一個(gè)胖子當(dāng)著我的面吹牛聂抢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棠众,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼琳疏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了闸拿?” 一聲冷哼從身側(cè)響起空盼,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎新荤,沒(méi)想到半個(gè)月后揽趾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苛骨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年篱瞎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痒芝。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俐筋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出严衬,到底是詐尸還是另有隱情澄者,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布请琳,位于F島的核電站粱挡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏俄精。R本人自食惡果不足惜抱怔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘀倒。 院中可真熱鬧屈留,春花似錦局冰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至勇蝙,卻和暖如春沫勿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背味混。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工产雹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翁锡。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓蔓挖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親馆衔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瘟判,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容