2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

25個(gè)最基本的JavaScript面試問(wèn)題及答案

 請(qǐng)嫁給愛(ài)情 2017-09-15

1、使用 typeof bar === 'object' 來(lái)確定 bar 是否是對(duì)象的潛在陷阱是什么?如何避免這個(gè)陷阱?


盡管 typeof bar === 'object' 是檢查 bar 是否對(duì)象的可靠方法,令人驚訝的是在JavaScript中 null 也被認(rèn)為是對(duì)象!


因此,令大多數(shù)開(kāi)發(fā)人員驚訝的是,下面的代碼將輸出 true (而不是false) 到控制臺(tái):

var bar = null;   console.log(typeof bar === 'object');  // logs true!

只要清楚這一點(diǎn),同時(shí)檢查 bar 是否為 null,就可以很容易地避免問(wèn)題:

console.log((bar !== null) && (typeof bar === 'object'));  // logs false

要答全問(wèn)題,還有其他兩件事情值得注意:


首先,上述解決方案將返回 false,當(dāng) bar 是一個(gè)函數(shù)的時(shí)候。在大多數(shù)情況下,這是期望行為,但當(dāng)你也想對(duì)函數(shù)返回 true 的話(huà),你可以修改上面的解決方案為:

console.log((bar !== null) && ((typeof bar === 'object') || (typeof bar === 'function')));

第二,上述解決方案將返回 true,當(dāng) bar 是一個(gè)數(shù)組(例如,當(dāng) var bar = [];)的時(shí)候。在大多數(shù)情況下,這是期望行為,因?yàn)閿?shù)組是真正的對(duì)象,但當(dāng)你也想對(duì)數(shù)組返回 false 時(shí),你可以修改上面的解決方案為:

console.log((bar !== null) && (typeof bar === 'object') && (toString.call(bar) !== '[object Array]'));

或者,如果你使用jQuery的話(huà):

console.log((bar !== null) && (typeof bar === 'object') && (! $.isArray(bar)));

2.下面的代碼將輸出什么到控制臺(tái),為什么?

(function(){     var a = b = 3;   })();   console.log('a defined? ' + (typeof a !== 'undefined'));   console.log('b defined? ' + (typeof b !== 'undefined'));

由于 a 和 b 都定義在函數(shù)的封閉范圍內(nèi),并且都始于 var關(guān)鍵字,大多數(shù)JavaScript開(kāi)發(fā)人員期望 typeof a 和 typeof b 在上面的例子中都是undefined。


然而,事實(shí)并非如此。這里的問(wèn)題是,大多數(shù)開(kāi)發(fā)人員將語(yǔ)句 var a = b = 3; 錯(cuò)誤地理解為是以下聲明的簡(jiǎn)寫(xiě):

var b = 3;
var a = b;

但事實(shí)上,var a = b = 3; 實(shí)際是以下聲明的簡(jiǎn)寫(xiě):

b = 3;   var a = b;

因此(如果你不使用嚴(yán)格模式的話(huà)),該代碼段的輸出是:

a defined? false  
b defined? true

但是, b 如何才能被定義在封閉函數(shù)的范圍之外呢?是的,既然語(yǔ)句 var a = b = 

3; 是語(yǔ)句 b = 3; 和 var a = b;的簡(jiǎn)寫(xiě), b 最終成為了一個(gè)全局變量(因?yàn)樗鼪](méi)有前綴 var 關(guān)鍵字),因此仍然在范圍內(nèi)甚至封閉函數(shù)之外。


需要注意的是,在嚴(yán)格模式下(即使用 use strict),語(yǔ)句var a = b = 3; 將生成ReferenceError: b is not defined的運(yùn)行時(shí)錯(cuò)誤,從而避免任何否則可能會(huì)導(dǎo)致的headfakes /bug。 (還是你為什么應(yīng)該理所當(dāng)然地在代碼中使用 use strict 的最好例子?。?/span>


3.下面的代碼將輸出什么到控制臺(tái),為什么?

var myObject = {       foo: 'bar',       func: function() {           var self = this;           console.log('outer func:  this.foo = ' + this.foo);           console.log('outer func:  self.foo = ' + self.foo);           (function() {               console.log('inner func:  this.foo = ' + this.foo);               console.log('inner func:  self.foo = ' + self.foo);           }());       }   };   myObject.func();

上面的代碼將輸出以下內(nèi)容到控制臺(tái):

outer func:  this.foo = bar   outer func:  self.foo = bar   inner func:  this.foo = undefined  
inner func:  self.foo = bar

在外部函數(shù)中, this 和self 兩者都指向了 myObject,因此兩者都可以正確地引用和訪(fǎng)問(wèn) foo。


在內(nèi)部函數(shù)中, this 不再指向 myObject。其結(jié)果是,this.foo 沒(méi)有在內(nèi)部函數(shù)中被定義,相反,指向到本地的變量self 保持在范圍內(nèi),并且可以訪(fǎng)問(wèn)。 (在ECMA 5之前,在內(nèi)部函數(shù)中的this 將指向全局的 window 對(duì)象;反之,因?yàn)樽鳛镋CMA 5,內(nèi)部函數(shù)中的功能this 是未定義的。)


4.封裝JavaScript源文件的全部?jī)?nèi)容到一個(gè)函數(shù)塊有什么意義及理由?


這是一個(gè)越來(lái)越普遍的做法,被許多流行的JavaScript庫(kù)(jQuery,Node.js等)采用。這種技術(shù)創(chuàng)建了一個(gè)圍繞文件全部?jī)?nèi)容的閉包,也許是最重要的是,創(chuàng)建了一個(gè)私有的命名空間,從而有助于避免不同JavaScript模塊和庫(kù)之間潛在的名稱(chēng)沖突。

這種技術(shù)的另一個(gè)特點(diǎn)是,允許一個(gè)易于引用的(假設(shè)更短的)別名用于全局變量。這通常用于,例如,jQuery插件中。jQuery允許你使用jQuery.noConflict(),來(lái)禁用 $ 引用到j(luò)Query命名空間。在完成這項(xiàng)工作之后,你的代碼仍然可以使用$ 利用這種閉包技術(shù),如下所示:

(function($) { /* jQuery plugin code referencing $ */ } )(jQuery);

5.在JavaScript源文件的開(kāi)頭包含 use strict 有什么意義和好處?


對(duì)于這個(gè)問(wèn)題,既簡(jiǎn)要又最重要的答案是,use strict 是一種在JavaScript代碼運(yùn)行時(shí)自動(dòng)實(shí)行更嚴(yán)格解析和錯(cuò)誤處理的方法。那些被忽略或默默失敗了的代碼錯(cuò)誤,會(huì)產(chǎn)生錯(cuò)誤或拋出異常。通常而言,這是一個(gè)很好的做法。


嚴(yán)格模式的一些主要優(yōu)點(diǎn)包括:


  • 使調(diào)試更加容易。那些被忽略或默默失敗了的代碼錯(cuò)誤,會(huì)產(chǎn)生錯(cuò)誤或拋出異常,因此盡早提醒你代碼中的問(wèn)題,你才能更快地指引到它們的源代碼。

  • 防止意外的全局變量。如果沒(méi)有嚴(yán)格模式,將值分配給一個(gè)未聲明的變量會(huì)自動(dòng)創(chuàng)建該名稱(chēng)的全局變量。這是JavaScript中最常見(jiàn)的錯(cuò)誤之一。在嚴(yán)格模式下,這樣做的話(huà)會(huì)拋出錯(cuò)誤。

  • 消除 this 強(qiáng)制。如果沒(méi)有嚴(yán)格模式,引用null或未定義的值到 this 值會(huì)自動(dòng)強(qiáng)制到全局變量。這可能會(huì)導(dǎo)致許多令人頭痛的問(wèn)題和讓人恨不得拔自己頭發(fā)的bug。在嚴(yán)格模式下,引用 null或未定義的 this 值會(huì)拋出錯(cuò)誤。

  • 不允許重復(fù)的屬性名稱(chēng)或參數(shù)值。當(dāng)檢測(cè)到對(duì)象(例如,var object = {foo: 'bar', foo: 'baz'};)中重復(fù)命名的屬性,或檢測(cè)到函數(shù)中(例如,function foo(val1, val2, val1){})重復(fù)命名的參數(shù)時(shí),嚴(yán)格模式會(huì)拋出錯(cuò)誤,因此捕捉幾乎可以肯定是代碼中的bug可以避免浪費(fèi)大量的跟蹤時(shí)間。

  • 使eval() 更安全。在嚴(yán)格模式和非嚴(yán)格模式下,eval() 的行為方式有所不同。最顯而易見(jiàn)的是,在嚴(yán)格模式下,變量和聲明在 eval() 語(yǔ)句內(nèi)部的函數(shù)不會(huì)在包含范圍內(nèi)創(chuàng)建(它們會(huì)在非嚴(yán)格模式下的包含范圍中被創(chuàng)建,這也是一個(gè)常見(jiàn)的問(wèn)題源)。

  • 在 delete使用無(wú)效時(shí)拋出錯(cuò)誤。delete操作符(用于從對(duì)象中刪除屬性)不能用在對(duì)象不可配置的屬性上。當(dāng)試圖刪除一個(gè)不可配置的屬性時(shí),非嚴(yán)格代碼將默默地失敗,而嚴(yán)格模式將在這樣的情況下拋出異常。


6.考慮以下兩個(gè)函數(shù)。它們會(huì)返回相同的東西嗎? 為什么相同或?yàn)槭裁床幌嗤?/span>

function foo1()   {     return {         bar: 'hello'     };   }   function foo2()   {     return     {         bar: 'hello'     };   }

出人意料的是,這兩個(gè)函數(shù)返回的內(nèi)容并不相同。更確切地說(shuō)是:

console.log('foo1 returns:');   console.log(foo1());   console.log('foo2 returns:');   console.log(foo2());

將產(chǎn)生:

foo1 returns:
Object {bar: 'hello'}foo2 returns:
undefined

這不僅是令人驚訝,而且特別讓人困惑的是, foo2()返回undefined卻沒(méi)有任何錯(cuò)誤拋出。


原因與這樣一個(gè)事實(shí)有關(guān),即分號(hào)在JavaScript中是一個(gè)可選項(xiàng)(盡管省略它們通常是非常糟糕的形式)。其結(jié)果就是,當(dāng)碰到 foo2()中包含 return語(yǔ)句的代碼行(代碼行上沒(méi)有其他任何代碼),分號(hào)會(huì)立即自動(dòng)插入到返回語(yǔ)句之后。


也不會(huì)拋出錯(cuò)誤,因?yàn)榇a的其余部分是完全有效的,即使它沒(méi)有得到調(diào)用或做任何事情(相當(dāng)于它就是是一個(gè)未使用的代碼塊,定義了等同于字符串 'hello'的屬性 bar)。


這種行為也支持放置左括號(hào)于JavaScript代碼行的末尾,而不是新代碼行開(kāi)頭的約定。正如這里所示,這不僅僅只是JavaScript中的一個(gè)風(fēng)格偏好。


7. NaN 是什么?它的類(lèi)型是什么?你如何可靠地測(cè)試一個(gè)值是否等于 NaN ?


NaN 屬性代表一個(gè)“不是數(shù)字”的值。這個(gè)特殊的值是因?yàn)檫\(yùn)算不能執(zhí)行而導(dǎo)致的,不能執(zhí)行的原因要么是因?yàn)槠渲械倪\(yùn)算對(duì)象之一非數(shù)字(例如, 'abc' / 4),要么是因?yàn)檫\(yùn)算的結(jié)果非數(shù)字(例如,除數(shù)為零)。


雖然這看上去很簡(jiǎn)單,但 NaN 有一些令人驚訝的特點(diǎn),如果你不知道它們的話(huà),可能會(huì)導(dǎo)致令人頭痛的bug。


首先,雖然 NaN 意味著“不是數(shù)字”,但是它的類(lèi)型,不管你信不信,是 Number:

console.log(typeof NaN === 'number');  // logs 'true'

此外, NaN 和任何東西比較——甚至是它自己本身!——結(jié)果是false:

console.log(NaN === NaN);  // logs 'false'

一種半可靠的方法來(lái)測(cè)試一個(gè)數(shù)字是否等于 NaN,是使用內(nèi)置函數(shù) isNaN(),但即使使用 isNaN() 依然并非是一個(gè)完美的解決方案。


一個(gè)更好的解決辦法是使用 value !== value,如果值等于NaN,只會(huì)產(chǎn)生true。另外,ES6提供了一個(gè)新的 Number.isNaN() 函數(shù),這是一個(gè)不同的函數(shù),并且比老的全局 isNaN() 函數(shù)更可靠。


8.下列代碼將輸出什么?并解釋原因。

console.log(0.1 + 0.2);   console.log(0.1 + 0.2 == 0.3);

一個(gè)稍微有點(diǎn)編程基礎(chǔ)的回答是:“你不能確定??赡軙?huì)輸出“0.3”和“true”,也可能不會(huì)。JavaScript中的數(shù)字和浮點(diǎn)精度的處理相同,因此,可能不會(huì)總是產(chǎn)生預(yù)期的結(jié)果?!?/span>


以上所提供的例子就是一個(gè)演示了這個(gè)問(wèn)題的典型例子。但出人意料的是,它會(huì)輸出:

0.30000000000000004  
false

9.討論寫(xiě)函數(shù) isInteger(x) 的可能方法,用于確定x是否是整數(shù)。


這可能聽(tīng)起來(lái)是小菜一碟,但事實(shí)上,這很瑣碎,因?yàn)镋CMAScript 6引入了一個(gè)新的正以此為目的 Number.isInteger() 函數(shù)。然而,之前的ECMAScript 6,會(huì)更復(fù)雜一點(diǎn),因?yàn)闆](méi)有提供類(lèi)似的 Number.isInteger() 方法。


問(wèn)題是,在ECMAScript規(guī)格說(shuō)明中,整數(shù)只概念上存在:即,數(shù)字值總是存儲(chǔ)為浮點(diǎn)值。


考慮到這一點(diǎn),最簡(jiǎn)單又最干凈的ECMAScript6之前的解決方法(同時(shí)也非常穩(wěn)健地返回 false ,即使一個(gè)非數(shù)字的值,如字符串或 null ,被傳遞給函數(shù))如下:

function isInteger(x) { return (x^0) === x; }

下面的解決方法也是可行的,雖然不如上面那個(gè)方法優(yōu)雅:

function isInteger(x) { return Math.round(x) === x; }

請(qǐng)注意 Math.ceil() 和 Math.floor() 在上面的實(shí)現(xiàn)中等同于 Math.round()。

或:

function isInteger(x) { return (typeof x === 'number') && (x % 1 === 0);

相當(dāng)普遍的一個(gè)不正確的解決方案是:

function isInteger(x) { return parseInt(x, 10) === x; }

雖然這個(gè)以 parseInt函數(shù)為基礎(chǔ)的方法在 x 取許多值時(shí)都能工作良好,但一旦 x 取值相當(dāng)大的時(shí)候,就會(huì)無(wú)法正常工作。問(wèn)題在于 parseInt() 在解析數(shù)字之前強(qiáng)制其第一個(gè)參數(shù)到字符串。因此,一旦數(shù)目變得足夠大,它的字符串就會(huì)表達(dá)為指數(shù)形式(例如, 1e+21)。因此,parseInt() 函數(shù)就會(huì)去解析 1e+21,但當(dāng)?shù)竭_(dá) e字符串的時(shí)候,就會(huì)停止解析,因此只會(huì)返回值 1。注意:

> String(1000000000000000000000)   '1e+21'  
> parseInt(1000000000000000000000, 10)   1  
> parseInt(1000000000000000000000, 10) === 1000000000000000000000  
false

10.下列代碼行1-4如何排序,使之能夠在執(zhí)行代碼時(shí)輸出到控制臺(tái)? 為什么?

(function() {       console.log(1);        setTimeout(function(){console.log(2)}, 1000);        setTimeout(function(){console.log(3)}, 0);        console.log(4);   })();

序號(hào)如下:

1  
4  
3  
2

讓我們先來(lái)解釋比較明顯而易見(jiàn)的那部分:


  • 1 和 4之所以放在前面,是因?yàn)樗鼈兪峭ㄟ^(guò)簡(jiǎn)單調(diào)用 console.log() 而沒(méi)有任何延遲輸出的

  • 2 之所以放在 3的后面,是因?yàn)?nbsp;2 是延遲了1000毫秒(即,1秒)之后輸出的,而 3 是延遲了0毫秒之后輸出的。


好的。但是,既然 3 是0毫秒延遲之后輸出的,那么是否意味著它是立即輸出的呢?如果是的話(huà),那么它是不是應(yīng)該在 4 之前輸出,既然 4 是在第二行輸出的?


要回答這個(gè)問(wèn)題,你需要正確理解JavaScript的事件和時(shí)間設(shè)置。


瀏覽器有一個(gè)事件循環(huán),會(huì)檢查事件隊(duì)列和處理未完成的事件。例如,如果時(shí)間發(fā)生在后臺(tái)(例如,腳本的 onload 事件)時(shí),瀏覽器正忙(例如,處理一個(gè) onclick),那么事件會(huì)添加到隊(duì)列中。當(dāng)onclick處理程序完成后,檢查隊(duì)列,然后處理該事件(例如,執(zhí)行 onload 腳本)。


同樣的, setTimeout() 也會(huì)把其引用的函數(shù)的執(zhí)行放到事件隊(duì)列中,如果瀏覽器正忙的話(huà)。


當(dāng)setTimeout()的第二個(gè)參數(shù)為0的時(shí)候,它的意思是“盡快”執(zhí)行指定的函數(shù)。具體而言,函數(shù)的執(zhí)行會(huì)放置在事件隊(duì)列的下一個(gè)計(jì)時(shí)器開(kāi)始。但是請(qǐng)注意,這不是立即執(zhí)行:函數(shù)不會(huì)被執(zhí)行除非下一個(gè)計(jì)時(shí)器開(kāi)始。這就是為什么在上述的例子中,調(diào)用 console.log(4) 發(fā)生在調(diào)用 console.log(3) 之前(因?yàn)檎{(diào)用 console.log(3) 是通過(guò)setTimeout被調(diào)用的,因此會(huì)稍微延遲)。


11.寫(xiě)一個(gè)簡(jiǎn)單的函數(shù)(少于80個(gè)字符),要求返回一個(gè)布爾值指明字符串是否為回文結(jié)構(gòu)。


下面這個(gè)函數(shù)在 str 是回文結(jié)構(gòu)的時(shí)候返回true,否則,返回false。

function isPalindrome(str) {       str = str.replace(/W/g, '').toLowerCase();       return (str == str.split('').reverse().join(''));   }

例如:

console.log(isPalindrome('level'));               // logs 'true'  
console.log(isPalindrome('levels'));              // logs 'false'  
console.log(isPalindrome('A car, a man, a maraca'));  // logs 'true'

12.寫(xiě)一個(gè) sum方法,在使用下面任一語(yǔ)法調(diào)用時(shí),都可以正常工作。

console.log(sum(2,3));   // Outputs 5  
console.log(sum(2)(3));  // Outputs 5

(至少)有兩種方法可以做到:


方法1

function sum(x) {     if (arguments.length == 2) {       return arguments[0] + arguments[1];     } else {       return function(y) { return x + y; };     }   }

在JavaScript中,函數(shù)可以提供到 arguments 對(duì)象的訪(fǎng)問(wèn),arguments 對(duì)象提供傳遞到函數(shù)的實(shí)際參數(shù)的訪(fǎng)問(wèn)。這使我們能夠使用 length 屬性來(lái)確定在運(yùn)行時(shí)傳遞給函數(shù)的參數(shù)數(shù)量。


如果傳遞兩個(gè)參數(shù),那么只需加在一起,并返回。


否則,我們假設(shè)它被以 sum(2)(3)這樣的形式調(diào)用,所以我們返回一個(gè)匿名函數(shù),這個(gè)匿名函數(shù)合并了傳遞到 sum()的參數(shù)和傳遞給匿名函數(shù)的參數(shù)。


方法2


function sum(x, y) {     if (y !== undefined) {       return x + y;     } else {       return function(y) { return x + y; };     }   }

當(dāng)調(diào)用一個(gè)函數(shù)的時(shí)候,JavaScript不要求參數(shù)的數(shù)目匹配函數(shù)定義中的參數(shù)數(shù)量。如果傳遞的參數(shù)數(shù)量大于函數(shù)定義中參數(shù)數(shù)量,那么多余參數(shù)將簡(jiǎn)單地被忽略。另一方面,如果傳遞的參數(shù)數(shù)量小于函數(shù)定義中的參數(shù)數(shù)量,那么缺少的參數(shù)在函數(shù)中被引用時(shí)將會(huì)給一個(gè) undefined值。所以,在上面的例子中,簡(jiǎn)單地檢查第2個(gè)參數(shù)是否未定義,就可以相應(yīng)地確定函數(shù)被調(diào)用以及進(jìn)行的方式。


13.請(qǐng)看下面的代碼片段:

for (var i = 0; i <>5; i++) {        var btn = document.createElement('button');        btn.appendChild(document.createTextNode('Button ' + i));        btn.addEventListener('click', function(){ console.log(i); });        document.body.appendChild(btn);      }

(a)當(dāng)用戶(hù)點(diǎn)擊“Button 4”的時(shí)候會(huì)輸出什么到控制臺(tái),為什么?(b)提供一個(gè)或多個(gè)備用的可按預(yù)期工作的實(shí)現(xiàn)方案。


(a)無(wú)論用戶(hù)點(diǎn)擊什么按鈕,數(shù)字5將總會(huì)輸出到控制臺(tái)。這是因?yàn)?,?dāng) onclick 方法被調(diào)用(對(duì)于任何按鈕)的時(shí)候, for 循環(huán)已經(jīng)結(jié)束,變量 i 已經(jīng)獲得了5的值。(面試者如果能夠談一談?dòng)嘘P(guān)如何執(zhí)行上下文,可變對(duì)象,激活對(duì)象和內(nèi)部“范圍”屬性貢有助于閉包行為,則可以加分)。


(b)要讓代碼工作的關(guān)鍵是,通過(guò)傳遞到一個(gè)新創(chuàng)建的函數(shù)對(duì)象,在每次傳遞通過(guò) for 循環(huán)時(shí),捕捉到 i 值。下面是三種可能實(shí)現(xiàn)的方法:

for (var i = 0; i <>5; i++) {     var btn = document.createElement('button');     btn.appendChild(document.createTextNode('Button ' + i));     btn.addEventListener('click', (function(i) {       return function() { console.log(i); };     })(i));     document.body.appendChild(btn);   }

或者,你可以封裝全部調(diào)用到在新匿名函數(shù)中的 btn.addEventListener :

for (var i = 0; i <>5; i++) {     var btn = document.createElement('button');     btn.appendChild(document.createTextNode('Button ' + i));     (function (i) {       btn.addEventListener('click', function() { console.log(i); });     })(i);     document.body.appendChild(btn);   }

也可以調(diào)用數(shù)組對(duì)象的本地 forEach 方法來(lái)替代 for 循環(huán):

['a', 'b', 'c', 'd', 'e'].forEach(function (value, i) {     var btn = document.createElement('button');     btn.appendChild(document.createTextNode('Button ' + i));     btn.addEventListener('click', function() { console.log(i); });     document.body.appendChild(btn);   });

14.下面的代碼將輸出什么到控制臺(tái),為什么?

var arr1 = 'john'.split('');   var arr2 = arr1.reverse();   var arr3 = 'jones'.split('');   arr2.push(arr3);   console.log('array 1: length=' + arr1.length + ' last=' + arr1.slice(-1));   console.log('array 2: length=' + arr2.length + ' last=' + arr2.slice(-1));

輸出結(jié)果是:

'array 1: length=5 last=j,o,n,e,s'  
'array 2: length=5 last=j,o,n,e,s'

arr1 和 arr2 在上述代碼執(zhí)行之后,兩者相同了,原因是:


  • 調(diào)用數(shù)組對(duì)象的 reverse() 方法并不只返回反順序的陣列,它也反轉(zhuǎn)了數(shù)組本身的順序(即,在這種情況下,指的是 arr1)。

  •  reverse() 方法返回一個(gè)到數(shù)組本身的引用(在這種情況下即,arr1)。其結(jié)果為,arr2 僅僅是一個(gè)到 arr1的引用(而不是副本)。因此,當(dāng)對(duì) arr2做了任何事情(即當(dāng)我們調(diào)用 arr2.push(arr3);)時(shí),arr1 也會(huì)受到影響,因?yàn)?nbsp;arr1 和 arr2 引用的是同一個(gè)對(duì)象。


這里有幾個(gè)側(cè)面點(diǎn)有時(shí)候會(huì)讓你在回答這個(gè)問(wèn)題時(shí),陰溝里翻船:


傳遞數(shù)組到另一個(gè)數(shù)組的 push() 方法會(huì)讓整個(gè)數(shù)組作為單個(gè)元素映射到數(shù)組的末端。其結(jié)果是,語(yǔ)句 arr2.push(arr3); 在其整體中添加 arr3 作為一個(gè)單一的元素到 arr2 的末端(也就是說(shuō),它并沒(méi)有連接兩個(gè)數(shù)組,連接數(shù)組是 concat() 方法的目的)。


和Python一樣,JavaScript標(biāo)榜數(shù)組方法調(diào)用中的負(fù)數(shù)下標(biāo),例如 slice() 可作為引用數(shù)組末尾元素的方法:例如,-1下標(biāo)表示數(shù)組中的最后一個(gè)元素,等等。


15.下面的代碼將輸出什么到控制臺(tái),為什么?

console.log(1 +  '2' + '2');   console.log(1 +  +'2' + '2');   console.log(1 +  -'1' + '2');   console.log(+'1' +  '1' + '2');   console.log( 'A' - 'B' + '2');   console.log( 'A' - 'B' + 2);

上面的代碼將輸出以下內(nèi)容到控制臺(tái):

'122'  
'32'  
'02'  
'112'  
'NaN2'  
NaN

原因是…


這里的根本問(wèn)題是,JavaScript(ECMAScript)是一種弱類(lèi)型語(yǔ)言,它可對(duì)值進(jìn)行自動(dòng)類(lèi)型轉(zhuǎn)換,以適應(yīng)正在執(zhí)行的操作。讓我們通過(guò)上面的例子來(lái)說(shuō)明這是如何做到的。


例1:1 + '2' + '2' 輸出:'122' 說(shuō)明: 1 + '2' 是執(zhí)行的第一個(gè)操作。由于其中一個(gè)運(yùn)算對(duì)象('2')是字符串,JavaScript會(huì)假設(shè)它需要執(zhí)行字符串連接,因此,會(huì)將 1 的類(lèi)型轉(zhuǎn)換為 '1', 1 + '2'結(jié)果就是 '12'。然后, '12' + '2' 就是 '122'。


例2: 1 + +'2' + '2' 輸出: '32' 說(shuō)明:根據(jù)運(yùn)算的順序,要執(zhí)行的第一個(gè)運(yùn)算是 +'2'(第一個(gè) '2' 前面的額外 + 被視為一元運(yùn)算符)。因此,JavaScript將 '2' 的類(lèi)型轉(zhuǎn)換為數(shù)字,然后應(yīng)用一元 + 號(hào)(即,將其視為一個(gè)正數(shù))。其結(jié)果是,接下來(lái)的運(yùn)算就是 1 + 2 ,這當(dāng)然是 3。然后我們需要在一個(gè)數(shù)字和一個(gè)字符串之間進(jìn)行運(yùn)算(即, 3 和 '2'),同樣的,JavaScript會(huì)將數(shù)值類(lèi)型轉(zhuǎn)換為字符串,并執(zhí)行字符串的連接,產(chǎn)生 '32'。


例3: 1 + -'1' + '2' 輸出: '02'  說(shuō)明:這里的解釋和前一個(gè)例子相同,除了此處的一元運(yùn)算符是 - 而不是 +。先是 '1' 變?yōu)?nbsp;1,然后當(dāng)應(yīng)用 - 時(shí)又變?yōu)榱?nbsp;-1 ,然后將其與 1相加,結(jié)果為 0,再將其轉(zhuǎn)換為字符串,連接最后的 '2' 運(yùn)算對(duì)象,得到 '02'。

例4: +'1' + '1' + '2' 輸出: '112' 說(shuō)明:雖然第一個(gè)運(yùn)算對(duì)象 '1'因?yàn)榍熬Y的一元 + 運(yùn)算符類(lèi)型轉(zhuǎn)換為數(shù)值,但又立即轉(zhuǎn)換回字符串,當(dāng)連接到第二個(gè)運(yùn)算對(duì)象 '1' 的時(shí)候,然后又和最后的運(yùn)算對(duì)象'2' 連接,產(chǎn)生了字符串 '112'。


例5: 'A' - 'B' + '2' 輸出: 'NaN2' 說(shuō)明:由于運(yùn)算符 -  不能被應(yīng)用于字符串,并且 'A' 和 'B' 都不能轉(zhuǎn)換成數(shù)值,因此,'A' - 'B'的結(jié)果是 NaN,然后再和字符串 '2' 連接,得到 'NaN2' 。


例6: 'A' - 'B' + 2 輸出: NaN 說(shuō)明:參見(jiàn)前一個(gè)例子, 'A' - 'B' 結(jié)果為 NaN。但是,應(yīng)用任何運(yùn)算符到NaN與其他任何的數(shù)字運(yùn)算對(duì)象,結(jié)果仍然是 NaN。

16.下面的遞歸代碼在數(shù)組列表偏大的情況下會(huì)導(dǎo)致堆棧溢出。在保留遞歸模式的基礎(chǔ)上,你怎么解決這個(gè)問(wèn)題?

var list = readHugeList();   var nextListItem = function() {       var item = list.pop();       if (item) {           // process the list item...          nextListItem();       }   };

潛在的堆棧溢出可以通過(guò)修改nextListItem 函數(shù)避免:

var list = readHugeList();   var nextListItem = function() {       var item = list.pop();       if (item) {           // process the list item...          setTimeout( nextListItem, 0);       }   };

堆棧溢出之所以會(huì)被消除,是因?yàn)槭录h(huán)操縱了遞歸,而不是調(diào)用堆棧。


當(dāng) nextListItem 運(yùn)行時(shí),如果 item不為空,timeout函數(shù)(nextListItem)就會(huì)被推到事件隊(duì)列,該函數(shù)退出,因此就清空調(diào)用堆棧。當(dāng)事件隊(duì)列運(yùn)行其timeout事件,且進(jìn)行到下一個(gè) item 時(shí),定時(shí)器被設(shè)置為再次調(diào)用 nextListItem。因此,該方法從頭到尾都沒(méi)有直接的遞歸調(diào)用,所以無(wú)論迭代次數(shù)的多少,調(diào)用堆棧保持清空的狀態(tài)。

17.JavaScript中的“閉包”是什么?請(qǐng)舉一個(gè)例子。


閉包是一個(gè)可以訪(fǎng)問(wèn)外部(封閉)函數(shù)作用域鏈中的變量的內(nèi)部函數(shù)。閉包可以訪(fǎng)問(wèn)三種范圍中的變量:這三個(gè)范圍具體為:(1)自己范圍內(nèi)的變量,(2)封閉函數(shù)范圍內(nèi)的變量,以及(3)全局變量。


下面是一個(gè)簡(jiǎn)單的例子:

var globalVar = 'xyz';   (function outerFunc(outerArg) {     var outerVar = 'a';     (function innerFunc(innerArg) {       var innerVar = 'b';       console.log(         'outerArg = ' + outerArg + '' +         'innerArg = ' + innerArg + '' +         'outerVar = ' + outerVar + '' +         'innerVar = ' + innerVar + '' +         'globalVar = ' + globalVar);     })(456);   })(123);

在上面的例子中,來(lái)自于 innerFunc, outerFunc和全局命名空間的變量都在 innerFunc的范圍內(nèi)。因此,上面的代碼將輸出如下:

outerArg = 123   innerArg = 456   outerVar = a   innerVar = b   globalVar = xyz

18.下面的代碼將輸出什么:


解釋你的答案。閉包在這里能起什么作用?


上面的代碼不會(huì)按預(yù)期顯示值0,1,2,3,和4,而是會(huì)顯示5,5,5,5,和5。

原因是,在循環(huán)中執(zhí)行的每個(gè)函數(shù)將整個(gè)循環(huán)完成之后被執(zhí)行,因此,將會(huì)引用存儲(chǔ)在 i中的最后一個(gè)值,那就是5。


閉包可以通過(guò)為每次迭代創(chuàng)建一個(gè)唯一的范圍,存儲(chǔ)范圍內(nèi)變量的每個(gè)唯一的值,來(lái)防止這個(gè)問(wèn)題,如下:

for (var i = 0; i <>5; i++) {       (function(x) {           setTimeout(function() { console.log(x); }, x * 1000 );       })(i);   }

這就會(huì)按預(yù)期輸出0,1,2,3,和4到控制臺(tái)。


19.以下代碼行將輸出什么到控制臺(tái)?

console.log('0 || 1 = '+(0 || 1));   console.log('1 || 2 = '+(1 || 2));   console.log('0 && 1 = '+(0 && 1));   console.log('1 && 2 = '+(1 && 2));

并解釋。


該代碼將輸出:

0 || 1 = 1  
1 || 2 = 1  
0 && 1 = 0  
1 && 2 = 2

在JavaScript中, || 和 &&都是邏輯運(yùn)算符,用于在從左至右計(jì)算時(shí),返回第一個(gè)可完全確定的“邏輯值”。


或( || )運(yùn)算符。在形如 X||Y的表達(dá)式中,首先計(jì)算X 并將其解釋執(zhí)行為一個(gè)布爾值。如果這個(gè)布爾值true,那么返回true(1),不再計(jì)算 Y,因?yàn)椤盎颉钡臈l件已經(jīng)滿(mǎn)足。如果這個(gè)布爾值為false,那么我們?nèi)匀徊荒苤?nbsp;X||Y是真是假,直到我們計(jì)算 Y,并且也把它解釋執(zhí)行為一個(gè)布爾值。


因此, 0 || 1 的計(jì)算結(jié)果為true(1),同理計(jì)算1 || 2。


與( &&)運(yùn)算符。在形如 X&&Y的表達(dá)式中,首先計(jì)算 X并將其解釋執(zhí)行為一個(gè)布爾值。如果這個(gè)布爾值為 false,那么返回 false(0),不再計(jì)算 Y,因?yàn)椤芭c”的條件已經(jīng)失敗。如果這個(gè)布爾值為true,但是,我們?nèi)匀徊恢?nbsp;X&&Y 是真是假,直到我們?nèi)ビ?jì)算 Y,并且也把它解釋執(zhí)行為一個(gè)布爾值。


不過(guò),關(guān)于 &&運(yùn)算符有趣的地方在于,當(dāng)一個(gè)表達(dá)式計(jì)算為“true”的時(shí)候,那么就返回表達(dá)式本身。這很好,雖然它在邏輯表達(dá)式方面計(jì)算為“真”,但如果你希望的話(huà)也可用于返回該值。這就解釋了為什么,有些令人奇怪的是, 1 && 2返回 2(而不是你以為的可能返回 true 或 1)。


20.執(zhí)行下面的代碼時(shí)將輸出什么?請(qǐng)解釋。

console.log(false == '0')
console.log(false === '0')

代碼將輸出:

true  
false

在JavaScript中,有兩種等式運(yùn)算符。三個(gè)等于運(yùn)算符 === 的作用類(lèi)似傳統(tǒng)的等于運(yùn)算符:如果兩側(cè)的表達(dá)式有著相同的類(lèi)型和相同的值,那么計(jì)算結(jié)果為true。而雙等于運(yùn)算符,會(huì)只強(qiáng)制比較它們的值。因此,總體上而言,使用 ===而不是 ==的做法更好。 !==vs !=亦是同理。


21.以下代碼將輸出什么?并解釋你的答案。

var a={},       b={key:'b'},       c={key:'c'};   a[b]=123;   a[c]=456;   console.log(a[b]);

這段代碼將輸出 456(而不是 123)。


原因?yàn)椋寒?dāng)設(shè)置對(duì)象屬性時(shí),JavaScript會(huì)暗中字符串化參數(shù)值。在這種情況下,由于 b 和 c都是對(duì)象,因此它們都將被轉(zhuǎn)換為'[object Object]'。結(jié)果就是, a[b]和a[c]均相當(dāng)于a['[object Object]'] ,并可以互換使用。因此,設(shè)置或引用 a[c]和設(shè)置或引用 a[b]完全相同。


22.以下代碼行將輸出什么到控制臺(tái)?

console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));

并解釋你的答案。


代碼將輸出10!的值(即10!或3628800)。


原因是:

f(1): returns n, which is 1  
f(2): returns 2 * f(1), which is 2  
f(3): returns 3 * f(2), which is 6  
f(4): returns 4 * f(3), which is 24  
f(5): returns 5 * f(4), which is 120  
f(6): returns 6 * f(5), which is 720  
f(7): returns 7 * f(6), which is 5040  
f(8): returns 8 * f(7), which is 40320  
f(9): returns 9 * f(8), which is 362880  
f(10): returns 10 * f(9), which is 3628800

命名函數(shù) f()遞歸地調(diào)用本身,當(dāng)調(diào)用 f(1)的時(shí)候,只簡(jiǎn)單地返回1。下面就是它的調(diào)用過(guò)程:


23.請(qǐng)看下面的代碼段。控制臺(tái)將輸出什么,為什么?

(function(x) {       return (function(y) {           console.log(x);       })(2)   })(1);

控制臺(tái)將輸出 1,即使從來(lái)沒(méi)有在函數(shù)內(nèi)部設(shè)置過(guò)x的值。原因是:


正如我們?cè)?/span>JavaScript招聘指南中解釋過(guò)的那樣,閉包是一個(gè)函數(shù),連同在閉包創(chuàng)建的時(shí)候,其范圍內(nèi)的所有變量或函數(shù)一起。在JavaScript中,閉包是作為一個(gè)“內(nèi)部函數(shù)”實(shí)施的:即,另一個(gè)函數(shù)主體內(nèi)定義的函數(shù)。閉包的一個(gè)重要特征是,內(nèi)部函數(shù)仍然有權(quán)訪(fǎng)問(wèn)外部函數(shù)的變量。


因此,在本例中,由于 x未在函數(shù)內(nèi)部中定義,因此在外部函數(shù)范圍中搜索定義的變量 x,且被發(fā)現(xiàn)具有1的值。


24.下面的代碼將輸出什么到控制臺(tái),為什么:

var hero = {       _name: 'John Doe',       getSecretIdentity: function (){           return this._name;       }   };   var stoleSecretIdentity = hero.getSecretIdentity;   console.log(stoleSecretIdentity());   console.log(hero.getSecretIdentity());

代碼有什么問(wèn)題,以及應(yīng)該如何修復(fù)。


代碼將輸出:

undefined   John Doe

第一個(gè) console.log之所以輸出 undefined,是因?yàn)槲覀冋趶?nbsp;hero對(duì)象提取方法,所以調(diào)用了全局上下文中(即窗口對(duì)象)的 stoleSecretIdentity(),而在此全局上下文中, _name屬性不存在。


其中一種修復(fù)stoleSecretIdentity() 函數(shù)的方法如下:

var stoleSecretIdentity = hero.getSecretIdentity.bind(hero);

25.創(chuàng)建一個(gè)給定頁(yè)面上的一個(gè)DOM元素,就會(huì)去訪(fǎng)問(wèn)元素本身及其所有子元素(不只是它的直接子元素)的函數(shù)。對(duì)于每個(gè)被訪(fǎng)問(wèn)的元素,函數(shù)應(yīng)該傳遞元素到提供的回調(diào)函數(shù)。


此函數(shù)的參數(shù)為:


DOM元素

回調(diào)函數(shù)(將DOM元素作為其參數(shù))


訪(fǎng)問(wèn)樹(shù)(DOM)的所有元素是經(jīng)典的深度優(yōu)先搜索算法應(yīng)用。下面是一個(gè)示范的解決方案:

function Traverse(p_element,p_callback) {      p_callback(p_element);      var list = p_element.children;      for (var i = 0; i < list.length;="" i++)="" {=""  =""   =""  =""  ="" traverse(list[i],p_callback);="">// recursive call     }   }

  • 來(lái)自:碼農(nóng)網(wǎng)

  • 鏈接:www.codeceo.com/article/25-essential-javascript-interview-questions.html

  • 英文原文:https://www./javascript/interview-questions

翻譯作者:碼農(nóng)網(wǎng) – 小峰

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多