37個JavaScript基礎口試題目和解答

1、運用typeof bar ===“object”來一定bar是不是是一個對象時有什麼潛伏的缺點?這個圈套怎樣防備?

只管typeof bar ===“object”是搜檢bar是不是是對象的牢靠要領,但JavaScript中使人驚奇的題目是_null_也被認為是一個對象!

因此,下面的代碼打印到掌握台的是true而不是false:

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

只需曉得這一點,就可以經由過程搜檢bar是不是為空來輕鬆防備該題目:

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

為了在我們的答案越發的完整,另有兩件事值得注重:

起首,假如bar是一個函數,上面的處理方案將返回false。在大多數狀況下,這是所希冀的行動,然則在您願望函數返回true的狀況下,您可以將上述處理方案修正成:

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

其次,假如bar是數組,則上述處理方案將返回true(比方,假如var bar = [];)。在大多數狀況下,這是所願望的行動,因為數組確實是對象,然則在您想要對數組也是false的狀況下,可以將上述處理方案修正成:

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

然則,另有一個替代要領對空值,數組和函數返回false,但關於對象則為true:

console.log((bar !== null) && (bar.constructor === Object));

或許,假如您運用jQuery:

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

ES5使得數組的狀況非常簡樸,包括它本身的空搜檢:

console.log(Array.isArray(bar));

2、下面的代碼將輸出到掌握台的是什麼,為何?

(function(){
  var a = b = 3;
})();

console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));

因為a和b都在函數的關閉局限內定義,而且因為它們地點的行以var關鍵字開首,因此大多數JavaScript開發人員會願望typeof a和typeof b在上面的示例中都未定義。

然則,狀況並非云云。這裏的題目是大多數開發人員毛病地輿解語句var a = b = 3;以下簡寫為:

var b = 3;
var a = b;

但現實上,var a = b = 3;現實上是速記:

b = 3;
var a = b;

因此(假如您不運用嚴厲情勢),代碼片斷的輸出將為:

a defined? false
b defined? true

然則怎樣在關閉函數的局限以外定義b?那末,因為聲明var a = b = 3;是語句b = 3的簡寫;而且var a = b; b終究成為一個全局變量(因為它不在var關鍵字背面),因此它依然在作用域內,縱然在關閉函數以外。

注重,在嚴厲情勢下(即,運用strict),語句var a = b = 3;會發作一個ReferenceError的運轉時毛病:b沒有定義,從而防備了可以致使的任何頭headfakes/bugs。 (這就是為何你應當在你的代碼中運用strict,一個重要的例子!)

3、下面的代碼將輸出到掌握台的是什麼?,為何?

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();

以上代碼將輸出到掌握台:

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

在外部函數中,this和self都援用myObject,因此都可以正確地援用和接見foo。

但在內部函數中,這不再指向myObject。因此,this.foo在內部函數中是未定義的,而對局部變量self的援用依然在局限內而且可以在那裡接見。

4、在功用塊中封裝JavaScript源文件的悉數內容的重要性和緣由是什麼?

這是一種日趨廣泛的做法,被許多盛行的JavaScript庫(jQuery,Node.js等)所採納。這類手藝在文件的悉數內容四周建立一個閉包,這可以最重要的是建立一個私有稱號空間,從而有助於防備差別JavaScript模塊和庫之間的潛伏稱號爭執。

這類手藝的另一個特點是為全局變量供應一個輕易援用(可以更短)的別號。比方,這一般用於jQuery插件。 jQuery許可您運用jQuery.noConflict()來禁用對jQuery稱號空間的$援用。假如如許做了,你的代碼依然可以運用$運用閉包手藝,以下所示:

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

5、在JavaScript源文件的開首包括’use strict’的意義和有什麼長處?

這裏最簡樸也是最重要的答案是use strict是_一種在運轉時自動實行更嚴厲的JavaScript代碼剖析和毛病處置懲罰的要領_。假如代碼毛病被疏忽或失利,將會發作毛病或拋出非常。總的來說,這是一個很好的做法。

嚴厲情勢的一些重要長處包括:

  • 使調試更輕易。 假如代碼毛病原本會被疏忽或失利,那末如今將會發作毛病或拋出非常,從而更快地發明代碼中的題目,並更快地指引它們的源代碼。
  • 防備不測全局。 假如沒有嚴厲情勢,將值賦給未聲明的變量會自動建立一個具有該稱號的全局變量。這是JavaScript中最罕見的毛病之一。在嚴厲情勢下,嘗試如許做會激發毛病。
  • 消弭隱蔽要挾。在沒有嚴厲情勢的狀況下,對null或undefined的這個值的援用會自動強迫到全局。這可以會致使許多_headfakes_和_pull-out-your-hair_範例的毛病。在嚴厲情勢下,援用null或undefined的這個值會激發毛病。
  • 不許可反覆的參數值。 嚴厲情勢在檢測到函數的反覆定名參數(比方,函數foo(val1,val2,val1){})時會激發毛病,從而捕捉代碼中險些可以一定存在的毛病,不然您可以會糟蹋大批的時候追蹤。

    • 注重:它曾經是(在ECMAScript 5中)strict情勢將制止反覆的屬性稱號(比方var object = {foo:“bar”,foo:“baz”};)然則從ECMAScript 2015 最先,就不再有這類狀況了。
  • 使eval()更平安。 eval()在嚴厲情勢和非嚴厲情勢下的行動體式格局有些差別。最重要的是,在嚴厲情勢下,在eval()語句內部聲明的變量和函數不會在包括局限中建立(它們是以非嚴厲情勢在包括局限中建立的,這也多是題目的罕見泉源)。
  • 拋出無效的運用毛病的刪除符。 刪除操縱符(用於從對象中刪除屬性)不能用於對象的不可設置屬性。當試圖刪除一個不可設置的屬性時,非嚴厲代碼將自動失利,而在這類狀況下,嚴厲情勢會激發毛病。

6、斟酌下面的兩個函數。他們都邑返回一樣的值嗎?為何或許為何不?

function foo1()
{
  return {
      bar: "hello"
  };
}

function foo2()
{
  return
  {
      bar: "hello"
  };
}

使人驚奇的是,這兩個函數不會返回雷同的效果。而是:

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

會發作:

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

這不僅使人驚奇,而且迥殊使人煩惱的是,foo2()返回未定義而沒有激發任何毛病。

緣由與JavaScript中分號在手藝上是可選的現實有關(只管疏忽它們一般黑白常蹩腳的情勢)。因此,在foo2()中碰到包括return語句的行(沒有其他內容)時,_會在return語句以後馬上自動插進去分號。_

因為代碼的其餘部份是完整有效的,縱然它沒有被挪用或做任何事情(它只是一個未運用的代碼塊,它定義了一個屬性欄,它即是字符串“hello”),所以不會拋出任何毛病。

這類行動也被認為是遵照了在JavaScript中將一行開首大括號放在行尾的商定,而不是在新行的開首。云云處所示,這不僅僅是JavaScript中的一種作風偏好。

7、什麼是NaN?它的範例是什麼?怎樣牢靠地測試一個值是不是即是NaN?

NaN屬性示意“不是数字”的值。這個特別值是因為一個操縱數黑白数字的(比方“abc”/ 4)或許因為操縱的效果黑白数字而沒法實行的。

雖然這看起來很簡樸,但NaN有一些使人驚奇的特性,假如人們沒有意想到這些特性,就會致使bug。

一方面,雖然NaN的意義是“不是数字”,但它的範例是,数字:

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

別的,NaN比擬任何事情 – 以至本身! – 是false:

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

測試数字是不是即是NaN的半牢靠要領是運用內置函數isNaN(),但縱然運用isNaN()也不是一個好的處理方案。.

一個更好的處理方案要麼是運用value!==值,假如該值即是NaN,那末只會天生true。別的,ES6供應了一個新的Number.isNaN()函數 ,它與舊的全局isNaN()函數差別,也越發牢靠。

8、下面的代碼輸出什麼?詮釋你的答案。

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

對這個題目的一個有修養的回覆是:“你不能一定。它可以打印出0.3和true,或許可以不打印。 JavaScript中的数字悉數用浮點精度處置懲罰,因此可以不會老是發作預期的效果。“

上面供應的示例是演示此題目的典範案例。使人驚奇的是,它會打印出來:

0.30000000000000004
false

一個典範的處理方案是比較兩個数字與特別常數Number.EPSILON之間的相對差值:

function areTheNumbersAlmostEqual(num1, num2) {
    return Math.abs( num1 - num2 ) < Number.EPSILON;
}
console.log(areTheNumbersAlmostEqual(0.1 + 0.2, 0.3));

議論寫函數的可以要領isInteger(x),它一定x是不是是一個整數。

這聽起來很尋常,現實上,ECMAscript 6為此恰好引入了一個新的Number.isInteger()函數,這是眇乎小哉的。然則,在ECMAScript 6之前,這有點龐雜,因為沒有供應與Number.isInteger()要領等價的要領。

題目在於,在ECMAScript範例中,整數只在概念上存在;即數值一直作為浮點值存儲。

斟酌到這一點,最簡樸,最潔凈的ECMAScript-6之前的處理方案(縱然將非数字值(比方字符串或空值)通報給該函數,該處理方案也具有充足的牢靠性以返回false)將成為以下用法按位異或運算符:

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

下面的處理方案也可以事情,只管不如上面那樣雅緻

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

請注重,在上面的完成中Math.ceil()或Math.floor()可以一樣運用(而不是Math.round())。

或許:

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

一個相稱罕見的不正確的處理方案以下:

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

雖然這個基於parseInt的要領對許多x值很有效,但一旦x變得相稱大,它將沒法一般事情。題目是parseInt()在剖析数字之前將其第一個參數強迫轉換為字符串。因此,一旦数字變得充足大,其字符串示意將以指數情勢顯現(比方1e + 21)。因此,parseInt()將嘗試剖析1e + 21,然則當它抵達e字符時將住手剖析,因此將返回值1.視察:

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

9、實行下面的代碼時,按什麼遞次將数字1-4紀錄到掌握台?為何?

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

這些值將按以下遞次紀錄:

1
4
3
2

我們先來詮釋一下這些可以更加顯著的部份:

  • 起首顯現1和4,因為它們是經由過程簡樸挪用console.log()而沒有任何耽誤紀錄的
  • 在3以後顯現,因為在耽誤1000毫秒(即1秒)以後紀錄2,而在0毫秒的耽誤以後紀錄3。

好的。然則,假如在耽誤0毫秒后紀錄3,這是不是意味着它正在被馬上紀錄?而且,假如是如許,不該當在4之前紀錄它,因為4是由背面的代碼行紀錄的嗎?

答案與正確理解JavaScript事宜和時候有關。 .

瀏覽器有一個事宜輪迴,它搜檢事宜行列並處置懲罰未決事宜。比方,假如在瀏覽器忙碌時(比方,處置懲罰onclick)在背景發作事宜(比方劇本onload事宜),則該事宜被附加到行列中。當onclick處置懲罰順序完成時,將搜檢行列並處置懲罰該事宜(比方,實行onload劇本)。

一樣,假如瀏覽器忙碌,setTimeout()也會將其援用函數的實行放入事宜行列中。

當值為零作為setTimeout()的第二個參數通報時,它將嘗試“儘快”實行指定的函數。具體來說,函數的實行安排在事宜行列中,以鄙人一個計時器滴答時發作。但請注重,這不是直接的;該功用不會實行,直到下一個滴答聲。這就是為安在上面的例子中,挪用console.log(4)發作在挪用console.log(3)之前(因為挪用console.log(3)是經由過程setTimeout挪用的,所以輕微耽誤了一點)。

10、編寫一個簡樸的函數(少於160個字符),返回一個布爾值,指點字符串是不是是palindrome

假如str是迴文,以下一行函數將返回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'

11、寫一個sum要領,當運用下面的語法挪用時它將一般事情。

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

有(最少)兩種要領可以做到這一點:

METHOD 1

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

在JavaScript中,函數供應對參數對象的接見,該對象供應對通報給函數的現實參數的接見。這使我們可以運用length屬性在運轉時一定通報給函數的參數的數目

假如通報兩個參數,我們只需將它們相加並返回。

不然,我們假定它是以sum(2)(3)的情勢被挪用的,所以我們返回一個匿名函數,它將通報給sum()(在本例中為2)的參數和通報給匿名函數的參數這類狀況3)。

METHOD 2

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

當函數被挪用時,JavaScript不須要參數的數目來婚配函數定義中參數的數目。假如通報的參數數目超過了函數定義中參數的數目,則超越的參數將被疏忽。另一方面,假如通報的參數數目少於函數定義中的參數數目,則在函數內援用時,缺乏的參數將具有未定義的值。因此,在上面的例子中,經由過程簡樸地搜檢第二個參數是不是未定義,我們可以一定函數被挪用的體式格局並響應地繼承。

12、斟酌下面的代碼片斷

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) 當用戶點擊“按鈕4”時,什麼被紀錄到掌握台?為何?

(b) 供應一個或多個可按預期事情的替代完成。

答:

(a) 不管用戶點擊哪一個按鈕,数字5將一直紀錄到掌握台。這是因為,在挪用onclick要領(關於任何按鈕)時,for輪迴已完成,而且變量i已具有值5.(假如受訪者曉得充足的話就可以取得嘉獎點數關於實行高低文,變量對象,激活對象和內部“局限”屬性怎樣影響閉包行動。)

(b) 使這項事情的關鍵是經由過程將它通報給新建立的函數對象來捕捉每次經由過程for輪迴的i的值。以下是四種可以的要領來完成這一點:

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);
}

或許,您可以將新的匿名函數中的全部挪用包裝為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);
}

或許,我們可以經由過程挪用數組對象的原生forEach要領來替代for輪迴:

['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);
});

末了,最簡樸的處理方案,假如你在ES6 / ES2015高低文中,就是運用let i而不是var i:

for (let 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);
}

13、假定d是局限內的“空”對象:

var d = {};

…運用下面的代碼完成了什麼?

[ 'zebra', 'horse' ].forEach(function(k) {
    d[k] = undefined;
});

上面顯現的代碼片斷在對象d上設置了兩個屬性。抱負狀況下,對具有未設置鍵的JavaScript對象實行的查找評價為未定義。然則運轉這段代碼會將這些屬性標記為對象的“本身的屬性”。

這是確保對象具有一組給定屬性的有效戰略。將該對象通報給Object.keys將返回一個包括這些設置鍵的數組(縱然它們的值未定義)。

14、下面的代碼將輸出到掌握台,為何?

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

紀錄的輸出將是:

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

arr1和arr2是雷同的(即[‘n’,’h’,’o’,’j’,[‘j’,’o’,’n’,’e’,’s’]])上述代碼因為以下緣由而被實行:

  • 挪用數組對象的reverse()要領不僅以相反的遞次返回數組,它還顛倒了數組本身的遞次(即在這類狀況下,arr1)。
  • reverse()要領返回對數組本身的援用(即,在這類狀況下為arr1)。因此,arr2僅僅是對arr1的援用(而不是副本)。因此,當對arr2做任何事情時(即,當我們挪用arr2.push(arr3);)時,arr1也會受到影響,因為arr1和arr2隻是對同一個對象的援用。

這裡有幾個看法可以讓人們回覆這個題目:

  • 將數組通報給另一個數組的push()要領會將全部數組作為單個元素推入數組的末端。效果,聲明arr2.push(arr3);將arr3作為一個團體增加到arr2的末端(即,它不銜接兩個數組,這就是concat()要領的用處)。
  • 像Python一樣,JavaScript在挪用像slice()如許的數組要領時,會認可負面下標,以此作為在數組末端援用元素的體式格局;比方,下標-1示意數組中的末了一個元素,依此類推。

15、下面的代碼將輸出到掌握台,為何?

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

以上代碼將輸出到掌握台:

"122"
"32"
"02"
"112"
"NaN2"
NaN

這是為何…

這裏的基礎題目是JavaScript(ECMAScript)是一種鬆懈範例的言語,它對值實行自動範例轉換以順應正在實行的操縱。讓我們來看看這是怎樣與上面的每一個例子舉行比較。

示例1:1 +“2”+“2”輸出:“122”申明:第一個操縱在1 +“2”中實行。因為个中一個操縱數(“2”)是一個字符串,所以JavaScript假定須要實行字符串銜接,因此將1的範例轉換為“1”,1 +“2”轉換為“12”。然後,“12”+“2”發作“122”。

示例2:1 + +“2”+“2”輸出:“32”申明:依據操縱遞次,要實行的第一個操縱是+“2”(第一個“2”之前的分外+被視為一個一元運算符)。因此,JavaScript將“2”的範例轉換為数字,然後將一元+標記運用於它(即將其視為正數)。效果,下一個操縱如今是1 + 2,固然這會發作3.然則,我們有一個数字和一個字符串之間的操縱(即3和“2”),所以JavaScript再次轉換數值賦給一個字符串並實行字符串銜接,發作“32”。

示例3:1 + – “1”+“2”輸出:“02”申明:這裏的詮釋與前面的示例雷同,只是一元運算符是 – 而不是+。因此,“1”變成1,然後在運用 – 時將其變成-1,然後將其加1到發作0,然後轉換為字符串並與終究的“2”操縱數銜接,發作“02”。

示例4:+“1”+“1”+“2”輸出:“112”申明:只管第一個“1”操縱數是基於其前面的一元+運算符的數值範例轉換的,當它與第二個“1”操縱數銜接在一起時返回一個字符串,然後與終究的“2”操縱數銜接,發作字符串“112”。

示例5:“A” – “B”+“2”輸出:“NaN2”申明:因為 – 運算符不能運用於字符串,而且既不能將“A”也不能將“B”轉換為數值, “ – ”B“發作NaN,然後​​與字符串”2“串連發作”NaN2“。

例6:“A” – “B”+2輸出:NaN申明:在前面的例子中,“A” – “B”發作NaN。然則任何運算符運用於NaN和其他数字操縱數依然會發作NaN。

16、假如數組列表太大,以下遞歸代碼將致使客棧溢出。你怎樣處理這個題目,依然保存遞歸情勢?

var list = readHugeList();

var nextListItem = function() {
    var item = list.pop();

    if (item) {
        // process the list item...
        nextListItem();
    }
};

經由過程修正nextListItem函數可以防備潛伏的客棧溢出,以下所示:

var list = readHugeList();

var nextListItem = function() {
    var item = list.pop();

    if (item) {
        // process the list item...
        setTimeout( nextListItem, 0);
    }
};

客棧溢出被消弭,因為事宜輪迴處置懲罰遞歸,而不是挪用客棧。當nextListItem運轉時,假如item不為null,則將超時函數(nextListItem)推送到事宜行列,而且函數退出,從而使挪用客棧清零。當事宜行列運轉超時事宜時,將處置懲罰下一個項目,並設置一個計時器以再次挪用nextListItem。因此,該要領從頭至尾不經由直接遞歸挪用即可處置懲罰,因此挪用客棧堅持清楚,不管迭代次數怎樣。

17、什麼是JavaScript中的“閉包”?舉一個例子。

閉包是一個內部函數,它可以接見外部(關閉)函數的作用域鏈中的變量。閉包可以接見三個局限內的變量;具體來說:(1)變量在其本身的局限內,(2)關閉函數局限內的變量,以及(3)全局變量。

這裡是一個例子:

var globalVar = "xyz";

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

在上面的例子中,innerFunc,outerFunc和全局稱號空間的變量都在innerFunc的局限內。上面的代碼將發作以下輸出:

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

18、以下代碼的輸出是什麼:

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

詮釋你的答案。怎樣在這裏運用閉包?

顯現的代碼示例不會顯現值0,1,2,3和4,這多是預期的;而是顯現5,5,5,5。

這是因為輪迴內實行的每一個函數將在全部輪迴完成后實行,因此一切函數都邑援用存儲在i中的末了一個值,即5。

經由過程為每次迭代建立一個唯一的作用域 ,可以運用閉包來防備這個題目,並將該變量的每一個唯一值存儲在其作用域中,以下所示:

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

這會發作將0,1,2,3和4紀錄到掌握台的可以效果。

ES2015高低文中,您可以在原始代碼中簡樸地運用let而不是var:

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

19、以下幾行代碼輸出到掌握台?

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中,都是||和&&是邏輯運算符,當從左向右盤算時返回第一個完整一定的“邏輯值”。

或(||)運算符。在情勢為X || Y的表達式中,起首盤算X並將其詮釋為布爾值。假云云布爾值為真,則返回true(1),而且不盤算Y,因為“或”前提已滿足。然則,假云云布爾值為“假”,我們依然不曉得X || Y是真照樣假,直到我們評價Y,並將其詮釋為布爾值。

因此,0 || 1評價為真(1),正如1 || 2。

和(&&)運算符。在X && Y情勢的表達式中,起首評價X並將其詮釋為布爾值。假云云布爾值為false,則返回false(0)而且不評價Y,因為“and”前提已失利。然則,假如這個布爾值為“真”,我們依然不曉得X && Y是真照樣假,直到我們評價Y,並將其詮釋為布爾值。

但是,&&運算符的風趣的地方在於,當表達式評價為“真”時,則返回表達式本身。這很好,因為它在邏輯表達式中被視為“真”,但也可以用於在您體貼時返回該值。這詮釋了為何,有點使人驚奇的是,1 && 2返回2(而你可以會希冀它返回true或1)。

20 、下面的代碼實行時輸出是什麼?申明。

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

該代碼將輸出:

true
false

在JavaScript中,有兩套相稱運算符。三重相稱運算符===的行動與任何傳統的相稱運算符雷同:假如兩側的兩個表達式具有雷同的範例和雷同的值,則盤算效果為true。但是,雙等號運算符在比較它們之前試圖強迫這些值。因此,一般運用===而不是==。關於!== vs!=也是云云。

21、以下代碼的輸出是什麼?詮釋你的答案。

var a={},
    b={key:'b'},
    c={key:'c'};

a[b]=123;
a[c]=456;

console.log(a[b]);

此代碼的輸出將是456(不是123)。

緣由以下:設置對象屬性時,JavaScript會隱式地將參數值串連起來。在這類狀況下,因為b和c都是對象,它們都將被轉換為“[object Object]”。因此,a [b]和a [c]都等價於[“[object Object]”],而且可以交換運用。因此,設置或援用[c]與設置或援用[b]完整雷同。

22、以下代碼將輸出到掌握台中.

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

該代碼將輸出10階乘的值(即10!或3,628,800)。

緣由以下:

定名函數f()以遞歸體式格局挪用本身,直到它挪用f(1),它簡樸地返回1.因此,這就是它的作用:

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

23 、斟酌下面的代碼片斷。掌握台的輸出是什麼,為何?

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

輸出將為1,縱然x的值從未在內部函數中設置。緣由以下:

正如我們的JavaScript僱用指南中所詮釋的,閉包是一個函數,以及建立閉包時在局限內的一切變量或函數。在JavaScript中,閉包被完成為“內部函數”;即在另一功用的主體內定義的功用。閉包的一個重要特性是內部函數依然可以接見外部函數的變量。

因此,在這個例子中,因為x沒有在內部函數中定義,所以在外部函數的作用域中搜刮一個定義的變量x,該變量的值為1。

24、以下代碼將輸出到掌握台以及為何

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

var stoleSecretIdentity = hero.getSecretIdentity;

console.log(stoleSecretIdentity());
console.log(hero.getSecretIdentity());

這段代碼有什麼題目,以及怎樣處理這個題目。

該代碼將輸出:

undefined
John Doe

第一個console.log打印未定義,因為我們從hero對象中提取要領,所以stoleSecretIdentity()在_name屬性不存在的全局高低文(即窗口對象)中被挪用。

修復stoleSecretIdentity()函數的一種要領以下:

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

25、建立一個函數,給定頁面上的DOM元素,將接見元素本身及其一切子女(_不僅僅是它的直接子元素_)。關於每一個接見的元素,函數應當將該元素通報給供應的回調函數。

該函數的參數應當是:

  • 一個 DOM 元素
  • 一個回調函數(以DOM元素作為參數)

接見樹中的一切元素(DOM)是[典範的深度優先搜刮算法]Depth-First-Search algorithm運用順序。以下是一個示例處理方案:

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
   }
}

27、在JavaScript中測試您的這些學問:以下代碼的輸出是什麼?

var length = 10;
function fn() {
    console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};

obj.method(fn, 1);

輸出:

10
2

為何不是10和5?

起首,因為fn作為函數要領的參數通報,函數fn的作用域(this)是窗口。 var length = 10;在窗口級別聲明。它也可以作為window.length或length或this.length來接見(當這個===窗口時)。

要領綁定到Object obj,obj.method用參數fn和1挪用。雖然要領只接收一個參數,但挪用它時已通報了兩個參數;第一個是函數回調,其他只是一個数字。

當在內部要領中挪用fn()時,該函數在全局級別作為參數通報,this.length將有權接見在Object obj中定義的var length = 10(全局聲明)而不是length = 5。

如今,我們曉得我們可以運用arguments []數組接見JavaScript函數中的恣意數目的參數。

因此arguments0隻不過是挪用fn()。在fn內里,這個函數的作用域成為參數數組,而且紀錄參數[]的長度將返回2。

因此輸出將如上所述。

28、斟酌下面的代碼。輸出是什麼,為何?

(function () {
    try {
        throw new Error();
    } catch (x) {
        var x = 1, y = 2;
        console.log(x);
    }
    console.log(x);
    console.log(y);
})();
1
undefined
2

var語句被掛起(沒有它們的值初始化)到它所屬的全局或函數作用域的頂部,縱然它位於with或catch塊內。然則,毛病的標識符只在catch塊內部可見。它相稱於:

(function () {
    var x, y; // outer and hoisted
    try {
        throw new Error();
    } catch (x /* inner */) {
        x = 1; // inner x, not the outer one
        y = 2; // there is only one y, which is in the outer scope
        console.log(x /* inner */);
    }
    console.log(x);
    console.log(y);
})();

29、這段代碼的輸出是什麼?

var x = 21;
var girl = function () {
    console.log(x);
    var x = 20;
};
girl ();

21,也不是20,效果是‘undefined’的

這是因為JavaScript初始化沒有被掛起。

(為何它不顯現21的全局值?緣由是當函數實行時,它搜檢是不是存在當地x變量但還沒有聲明它,因此它不會查找全局變量。 )

30、你怎樣克隆一個對象?

var obj = {a: 1 ,b: 2}
var objclone = Object.assign({},obj);

如今objclone的值是{a:1,b:2},但指向與obj差別的對象。

但請注重潛伏的缺點:Object.clone()只會實行淺拷貝,而不是深拷貝。這意味着嵌套的對象不會被複制。他們依然援用與原始雷同的嵌套對象:

let obj = {
    a: 1,
    b: 2,
    c: {
        age: 30
    }
};

var objclone = Object.assign({},obj);
console.log('objclone: ', objclone);

obj.c.age = 45;
console.log('After Change - obj: ', obj);           // 45 - This also changes
console.log('After Change - objclone: ', objclone); // 45
for (let i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, i * 1000 );
}

31、此代碼將打印什麼?

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

它會打印0 1 2 3 4,因為我們在這裏運用let而不是var。變量i只能在for輪迴的塊局限中看到。

32、以下幾行輸出什麼,為何?

console.log(1 < 2 < 3);
console.log(3 > 2 > 1);

第一條語句返回true,如預期的那樣。

第二個返回false是因為引擎怎樣針對<和>的操縱符關聯性事情。它比較從左到右,所以3> 2> 1 JavaScript翻譯為true> 1. true具有值1,因此它比較1> 1,這是毛病的。

33、怎樣在數組的開首增加元素?末了怎樣增加一個?

var myArray = ['a', 'b', 'c', 'd'];
myArray.push('end');
myArray.unshift('start');
console.log(myArray); // ["start", "a", "b", "c", "d", "end"]

運用ES6,可以運用擴大運算符:

myArray = ['start', ...myArray];
myArray = [...myArray, 'end'];

或許,簡而言之:

myArray = ['start', ...myArray, 'end'];

34、設想一下你有如許的代碼:

var a = [1, 2, 3];

a)這會致使崩潰嗎?

a[10] = 99;

b)這個輸出是什麼?

console.log(a[6]);

a)它不會崩潰。 JavaScript引擎將使陣列插槽3至9成為“空插槽”。

b)在這裏,a [6]將輸出未定義的值,但時隙仍為空,而不是未定義的。在某些狀況下,這多是一個重要的細微差別。比方,運用map()時,map()的輸出中的空插槽將堅持為空,但未定義的插槽將運用通報給它的函數重映照:

var b = [undefined];
b[2] = 1;
console.log(b);             // (3) [undefined, empty × 1, 1]
console.log(b.map(e => 7)); // (3) [7,         empty × 1, 7]

35、typeof undefined == typeof NULL的值是什麼?

該表達式將被評價為true,因為NULL將被視為任何其他未定義的變量。

注重:JavaScript辨別大小寫,我們在這裏運用NULL而不是null。

36、代碼返回後會怎樣?

console.log(typeof typeof 1);

string

typeof 1將返回“number”,typeof“number”將返回字符串。

37、以下代碼輸出什麼?為何?

var b = 1;
function outer(){
       var b = 2
    function inner(){
        b++;
        var b = 3;
        console.log(b)
    }
    inner();
}
outer();

輸出到掌握台將是“3”。

在這個例子中有三個閉包,每一個都有它本身的var b聲明。當挪用變量時,將根據從當地到全局的遞次搜檢閉包,直到找到實例。因為內部閉包有本身的b變量,這就是輸出。

別的,因為提拔內部的代碼將被詮釋以下:

function inner () {
    var b; // b is undefined
    b++; // b is NaN
    b = 3; // b is 3
    console.log(b); // output "3"
}

口試比辣手的手藝題目要多,所以這些僅僅是作為指點。並非每一個值得聘任的“A”候選人都可以回覆一切題目,也不會回覆他們都保證有“A”候選人。在這一天結束時,僱用依然是一門藝術,一門科學 – 另有許多事情。.

英文原文地點:https://www.toptal.com/javasc…

    原文作者:_小生_
    原文地址: https://segmentfault.com/a/1190000014761038
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞