2019-02-24

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):

varbar =null;console.log(typeofbar ==="object");// logs true!

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

console.log((bar !==null) && (typeofbar ==="object"));//logsfalse

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

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

console.log((bar !==null) && ((typeofbar ==="object") || (typeofbar ==="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) && (typeofbar ==="object") && (toString.call(bar) !=="[object Array]"));

或者缕减,如果你使用jQuery的話:

console.log((bar !==null) && (typeofbar ==="object") && (! $.isArray(bar)));

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

(function(){vara = b =3;})();console.log("a defined? "+ (typeofa !=='undefined'));console.log("b defined? "+ (typeofb !=='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ě):

varb =3;vara = b;

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

b=3;vara = b;

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

adefined?falsebdefined?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的最好例子1吮痢)

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

varmyObject = {? ? foo:"bar",? ? func:function(){varself =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 = barouter func:self.foo = barinner func:this.foo = undefinedinner func:self.foo = bar

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

在內(nèi)部函數(shù)中猜旬,this不再指向myObject。其結(jié)果是倦卖,this.foo沒(méi)有在內(nèi)部函數(shù)中被定義洒擦,相反,指向到本地的變量self保持在范圍內(nèi)怕膛,并且可以訪問(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ù)之間潛在的名稱沖突聊疲。

這種技術(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)建該名稱的全局變量。這是JavaScript中最常見(jiàn)的錯(cuò)誤之一寻行。在嚴(yán)格模式下霍掺,這樣做的話會(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ù)的屬性名稱或參數(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)槭裁床幌嗤?/p>

functionfoo1(){return{? ? ? bar:"hello"};}functionfoo2(){return{? ? ? bar:"hello"};}

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

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

將產(chǎn)生:

foo1returns:Object{bar:"hello"}foo2returns: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ì)導(dǎo)致令人頭痛的bug。

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

console.log(typeofNaN==="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é)果葛碧〗杞埽“

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

0.30000000000000004false

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ù))如下:

functionisInteger(x){return(x^0) === x; }

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

functionisInteger(x){returnMath.round(x) === x; }

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

或:

functionisInteger(x){return(typeofx ==='number') && (x %1===0);

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

functionisInteger(x){returnparseInt(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) ===1000000000000000000000false

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)?是延遲了1000毫秒(即槽地,1秒)之后輸出的迁沫,而3是延遲了0毫秒之后輸出的芦瘾。

好的。但是集畅,既然3是0毫秒延遲之后輸出的近弟,那么是否意味著它是立即輸出的呢?如果是的話挺智,那么它是不是應(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ì)列中屋吨,如果瀏覽器正忙的話蜒谤。

當(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筝野。

functionisPalindrome(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 5console.log(sum(2)(3));// Outputs 5

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

方法1

functionsum(x){if(arguments.length ==2) {returnarguments[0] +arguments[1];? }else{returnfunction(y){returnx + y; };? }}

在JavaScript中挥唠,函數(shù)可以提供到arguments對(duì)象的訪問(wèn)俊扳,arguments對(duì)象提供傳遞到函數(shù)的實(shí)際參數(shù)的訪問(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

functionsum(x, y){if(y !==undefined) {returnx + y;? }else{returnfunction(y){returnx + 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(vari =0; i <5; i++) {varbtn =document.createElement('button');? btn.appendChild(document.createTextNode('Button '+ i));? btn.addEventListener('click',function(){console.log(i); });document.body.appendChild(btn);}

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

(a)無(wú)論用戶點(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(vari =0; i <5; i++) {varbtn =document.createElement('button');? btn.appendChild(document.createTextNode('Button '+ i));? btn.addEventListener('click', (function(i){returnfunction(){console.log(i); };? })(i));document.body.appendChild(btn);}

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

for(vari =0; i <5; i++) {varbtn =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){varbtn =document.createElement('button');? btn.appendChild(document.createTextNode('Button '+ i));? btn.addEventListener('click',function(){console.log(i); });document.body.appendChild(btn);});

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

vararr1 ="john".split('');vararr2 = arr1.reverse();vararr3 ="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)閍rr1和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)?,然后當(dāng)應(yīng)用-時(shí)又變?yōu)榱?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)題惠勒?

varlist= readHugeList();varnextListItem =function(){varitem =list.pop();if(item) {// process the list item...nextListItem();? ? }};

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

varlist= readHugeList();varnextListItem =function(){varitem =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è)可以訪問(wèn)外部(封閉)函數(shù)作用域鏈中的變量的內(nèi)部函數(shù)栅葡。閉包可以訪問(wèn)三種范圍中的變量:這三個(gè)范圍具體為:(1)自己范圍內(nèi)的變量茉兰,(2)封閉函數(shù)范圍內(nèi)的變量,以及(3)全局變量妥畏。

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

varglobalVar ="xyz";(functionouterFunc(outerArg){varouterVar ='a';? (functioninnerFunc(innerArg){varinnerVar ='b';console.log("outerArg = "+ outerArg +"\n"+"innerArg = "+ innerArg +"\n"+"outerVar = "+ outerVar +"\n"+"innerVar = "+ innerVar +"\n"+"globalVar = "+ globalVar);? })(456);})(123);

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

outerArg=123innerArg=456outerVar= ainnerVar= bglobalVar= xyz

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

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

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

上面的代碼不會(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(vari =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=11||2=10&&1=01&&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)滿足。如果這個(gè)布爾值為false挨下,那么我們?nèi)匀徊荒苤繶||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)匀徊恢繶&&Y是真是假玷氏,直到我們?nèi)ビ?jì)算Y,并且也把它解釋執(zhí)行為一個(gè)布爾值腋舌。

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

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

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

代碼將輸出:

truefalse

在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.以下代碼將輸出什么?并解釋你的答案回怜。

vara={},? ? 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((functionf(n){return((n >1) ? n * f(n-1) : n)})(10));

并解釋你的答案怔球。

代碼將輸出10嚼酝!的值(即10!或3628800)竟坛。

原因是:

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

f(1): returns n, whichis1f(2): returns2* f(1), whichis2f(3): returns3* f(2), whichis6f(4): returns4* f(3), whichis24f(5): returns5* f(4), whichis120f(6): returns6* f(5), whichis720f(7): returns7* f(6), whichis5040f(8): returns8* f(7), whichis40320f(9): returns9* f(8), whichis362880f(10): returns10* f(9), whichis3628800

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è)贘avaScript招聘指南中解釋過(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)訪問(wèn)外部函數(shù)的變量件炉。

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

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

varhero = {? ? _name:'John Doe',? ? getSecretIdentity:function(){returnthis._name;? ? }};varstoleSecretIdentity = hero.getSecretIdentity;console.log(stoleSecretIdentity());console.log(hero.getSecretIdentity());

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

代碼將輸出:

undefinedJohn Doe

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

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

varstoleSecretIdentity = hero.getSecretIdentity.bind(hero);

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

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

DOM元素

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

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

functionTraverse(p_element,p_callback){? p_callback(p_element);varlist= p_element.children;for(vari =0; i

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末让虐,一起剝皮案震驚了整個(gè)濱河市紊撕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌澄干,老刑警劉巖逛揩,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異麸俘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)惧笛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)从媚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人患整,你說(shuō)我怎么就攤上這事拜效。” “怎么了各谚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵紧憾,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我昌渤,道長(zhǎng)赴穗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任膀息,我火速辦了婚禮般眉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘潜支。我一直安慰自己甸赃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布冗酿。 她就那樣靜靜地躺著埠对,像睡著了一般络断。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上项玛,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天妓羊,我揣著相機(jī)與錄音,去河邊找鬼稍计。 笑死躁绸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的臣嚣。 我是一名探鬼主播净刮,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼硅则!你這毒婦竟也來(lái)了淹父?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤怎虫,失蹤者是張志新(化名)和其女友劉穎暑认,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體大审,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蘸际,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徒扶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粮彤。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖姜骡,靈堂內(nèi)的尸體忽然破棺而出导坟,到底是詐尸還是另有隱情,我是刑警寧澤圈澈,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布惫周,位于F島的核電站,受9級(jí)特大地震影響康栈,放射性物質(zhì)發(fā)生泄漏递递。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一谅将、第九天 我趴在偏房一處隱蔽的房頂上張望漾狼。 院中可真熱鬧,春花似錦饥臂、人聲如沸逊躁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)稽煤。三九已至核芽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酵熙,已是汗流浹背轧简。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匾二,地道東北人哮独。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像察藐,于是被迫代替她去往敵國(guó)和親皮璧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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