1. 程式人生 > >主流公司的21個JavaScript面試問題

主流公司的21個JavaScript面試問題

21個基本JavaScript面試問題

21個基本JavaScript面試問題

問題1

1. undefinednot defined在JavaScript中有什麼區別?

在JavaScript中,如果您嘗試使用不存在且尚未宣告的變數,則JavaScript將引發錯誤var name is not defined並且指令碼將停止執行。但是,如果你使用typeof undeclared_variable,那麼它將返回undefined

在進一步討論之前,讓我們先了解宣告和定義之間的區別。

假設var x是一個宣告,因為你還沒有定義它所擁有的值,但你已經聲明瞭它的存在以及記憶體分配的需要。

> var x; // declaring x
> console.log(x); //output: undefined 

var x = 1是一個宣告和定義(我們也可以說我們正在進行初始化)。在上面的示例中,值的宣告和賦值發生在變數x的內聯中。在JavaScript中,呼叫您帶到當前範圍頂部的每個變數或函式宣告hoisting

賦值按順序發生,因此當我們嘗試訪問已宣告但尚未定義的變數時,我們將得到結果undefined

var x; // Declaration
if(typeof x === 'undefined') // Will return true

如果一個既未宣告也未定義的變數,當我們嘗試引用這樣的變數時,我們會得到結果not defined

> console.log(y);  // Output: ReferenceError: y is not defined

問題2

下面程式碼的輸出是什麼?

var y = 1;
  if (function f(){}) {
    y += typeof f;
  }
  console.log(y);

輸出將是1undefined。該if條件語句計算使用eval,所以eval(function f(){})回報率function f(){}(這是真的)。因此,在if語句內部,由於語句程式碼在執行時執行,因此執行typeof f返回,並且在執行時評估條件內的語句。undefinedifif

var k = 1;
  if (1) {
    eval(function foo(){});
    k += typeof foo;
  }
  console.log(k); 

上面的程式碼也會輸出1undefined

var k = 1;
  if (1) {
    function foo(){};
    k += typeof foo;
  }
  console.log(k); // output 1function

問題3

在JavaScript中建立真正的私有方法有什麼缺點?

在JavaScript中建立真正的私有方法的一個缺點是它們的記憶體效率非常低,因為將為每個例項建立該方法的新副本。

var Employee = function (name, company, salary) {
    this.name = name || "";       //Public attribute default value is null
    this.company = company || ""; //Public attribute default value is null
    this.salary = salary || 5000; //Public attribute default value is null

    // Private method
    var increaseSalary = function () {
        this.salary = this.salary + 1000;
    };

    // Public method
    this.dispalyIncreasedSalary = function() {
        increaseSlary();
        console.log(this.salary);
    };
};

// Create Employee class object
var emp1 = new Employee("John","Pluto",3000);
// Create Employee class object
var emp2 = new Employee("Merry","Pluto",2000);
// Create Employee class object
var emp3 = new Employee("Ren","Pluto",2500);

這裡的每個例項變數emp1emp2emp3有其自身的副本increaseSalary私有方法。

因此,作為建議,除非必要,否則不要使用私有方法。

問題4

什麼是JavaScript中的“閉包”?舉個例子

閉包是在另一個函式(稱為父函式)中定義的函式,並且可以訪問在父函式作用域中宣告和定義的變數。

閉包可以訪問三個範圍中的變數:

  • 在自己的範圍內宣告的變數
  • 在父函式範圍中宣告的變數
  • 在全域性名稱空間中宣告的變數
var globalVar = "abc"; 

// Parent self invoking function 
(function outerFunction (outerArg) { // begin of scope outerFunction
    // Variable declared in outerFunction function scope 
    var outerFuncVar = 'x';    
    // Closure self-invoking function 
    (function innerFunction (innerArg) { // begin of scope innerFunction
        // variable declared in innerFunction function scope
        var innerFuncVar = "y"; 
        console.log(          
            "outerArg = " + outerArg + "\n" +
            "outerFuncVar = " + outerFuncVar + "\n" +
            "innerArg = " + innerArg + "\n" +
            "innerFuncVar = " + innerFuncVar + "\n" +
            "globalVar = " + globalVar);
 
    }// end of scope innerFunction)(5); // Pass 5 as parameter 
}// end of scope outerFunction )(7); // Pass 7 as parameter 

innerFunction是在內部定義的閉包,outerFunction並且可以訪問在outerFunction作用域中宣告和定義的所有變數。另外,在另一個函式中定義的函式作為閉包將有權訪問在中宣告的變數global namespace

因此,上面程式碼的輸出將是:

outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc

問題5

編寫一個mul函式,在呼叫時將產生以下輸出:

console.log(mul(2)(3)(4)); // output : 24 
console.log(mul(4)(3)(4)); // output : 48

下面是答案,然後解釋它是如何工作的:

function mul (x) {
    return function (y) { // anonymous function 
        return function (z) { // anonymous function 
            return x * y * z; 
        };
    };
}

這裡mul函式接受第一個引數並返回一個匿名函式,它接受第二個引數並返回另一個匿名函式,該函式將獲取第三個引數並返回已傳遞的引數的乘法。

在JavaScript中,在另一個函式內定義的函式可以訪問外部函式的變數。因此,函式是一個第一類物件,也可以由其他函式返回,並作為引數傳遞給另一個函式。

  • 函式是Object型別的例項
  • 函式可以具有屬性,並具有返回其建構函式方法的連結
  • 函式可以儲存為變數
  • 函式可以作為引數傳遞給另一個函式
  • 可以從另一個函式返回一個函式

問題6

如何在JavaScript中清空陣列?

例如,

 var arrayList =  ['a','b','c','d','e','f'];

我們怎樣才能清空上面的陣列?

我們可以使用幾種方法來清空陣列,所以讓我們討論它們。

方法1

arrayList = []

上面的程式碼將變數設定arrayList為一個新的空陣列。如果您在其他任何地方都沒有對原始陣列的引用, 則建議使用此方法arrayList,因為它實際上會建立一個新的空陣列。您應該小心這種清空陣列的方法,因為如果您從另一個變數引用了這個陣列,那麼原始引用陣列將保持不變。

例如,

var arrayList = ['a','b','c','d','e','f']; // Created array 
var anotherArrayList = arrayList;  // Referenced arrayList by another variable 
arrayList = []; // Empty the array 
console.log(anotherArrayList); // Output ['a','b','c','d','e','f']

方法2

arrayList.length = 0;

上面的程式碼將通過將其長度設定為0來清除現有陣列。這種清空陣列的方式還會更新指向原始陣列的所有引用變數。因此,當您想要更新指向的所有引用變數時,此方法很有用arrayList

例如,

var arrayList = ['a','b','c','d','e','f']; // Created array 
var anotherArrayList = arrayList;  // Referenced arrayList by another variable 
arrayList.length = 0; // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []

方法3

arrayList.splice(0, arrayList.length);

上面的實現也將完美地運作。這種清空陣列的方法也將更新對原始陣列的所有引用。

var arrayList = ['a','b','c','d','e','f']; // Created array 
var anotherArrayList = arrayList;  // Referenced arrayList by another variable 
arrayList.splice(0, arrayList.length); // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []

方法4

while(arrayList.length){
  arrayList.pop();
}

上面的實現也可以清空陣列,但通常不建議經常使用此方法。

問題7

如何檢查物件是否是陣列?

找出物件是否是特定類的例項的最佳方法是使用以下toString方法Object.prototype

  var arrayList = [1,2,3];

型別檢查物件的最佳用例之一是我們在JavaScript中進行方法過載。例如,假設我們有一個名為的方法greet,它接受一個字串和一個字串列表。為了使我們的greet方法在兩種情況下都可行,我們需要知道傳遞的引數型別。它是單個值還是值列表?

function greet(param){
 	if(){ // here have to check whether param is array or not 
 	}else{
 	}
}

但是,由於上面的實現可能不一定檢查陣列的型別,我們可以檢查單個值字串並在else塊中放入一些陣列邏輯程式碼。例如:

function greet(param){
 	if(typeof param === 'string'){ 
 	}else{
 	  // If param is of type array then this block of code would execute
 	}
}

現在它的罰款,我們可與上述兩種實現去,但是當我們遇到這樣的情況該引數可以是single valuearrayobject型別,我們就會有麻煩。

回到檢查物件的型別,如前所述,我們可以使用Object.prototype.toString

if( Object.prototype.toString.call( arrayList ) === '[object Array]' ) {
    console.log('Array!');
}

如果您正在使用jQuery,那麼您也可以使用jQuery isArray方法:

if($.isArray(arrayList)){
    console.log('Array');
}else{
  	console.log('Not an array');
}

僅供參考,jQuery在Object.prototype.toString.call內部使用來檢查物件是否是陣列。

在現代瀏覽器中,您也可以使用

Array.isArray(arrayList);

Array.isArray Chrome 5,Firefox 4.0,IE 9,Opera 10.5和Safari 5支援

問題8

以下程式碼的輸出是什麼?

var output = (function(x){
    delete x;
    return x;
  })(0);
  
  console.log(output);

輸出將是0。的delete運算子用於從物件中刪除屬性。這x不是一個物件,而是一個區域性變數delete運算子不會影響區域性變數。

問題9

以下程式碼的輸出是什麼?

var x = 1;
var output = (function(){
    delete x;
    return x;
  })();
  
  console.log(output);

輸出將是1。該delete操作是用來刪除物件的屬性。這x不是一個物件,而是它的全域性變數型別number

問題10

下面程式碼的輸出是什麼?

var x = { foo : 1};
var output = (function(){
    delete x.foo;
    return x.foo;
  })();
  
  console.log(output);

輸出將是undefined。該delete操作是用來刪除物件的屬性。這裡,x是一個具有屬性的物件foo,因為它是一個自呼叫函式,我們foo將從物件中刪除該屬性x。在這樣做之後,當我們嘗試引用已刪除的屬性時foo,結果是undefined

問題11

下面程式碼的輸出是什麼?

var Employee = {
  company: 'xyz'
}
var emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company);

輸出將是xyz。在這裡,emp1物件都有company原型屬性。該delete操作不會刪除原型屬性。

emp1物件沒有公司作為自己的財產。你可以測試一下console.log(emp1.hasOwnProperty('company')); //output : false。但是,我們可以company直接從Employee物件中刪除屬性delete Employee.company。或者,我們也可以emp1使用__proto__屬性刪除物件delete emp1.__proto__.company

問題12

什麼是undefined x 1JavaScript?

var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];

當您執行上面的程式碼並輸入console.log(trees);Chrome開發者控制檯時,您將獲得["redwood", "bay", "cedar", undefined × 1, "maple"]。當您在Firefox的瀏覽器控制檯中執行程式碼時,您將獲得["redwood", "bay", "cedar", undefined, "maple"]。因此,很明顯Chrome瀏覽器有自己的方式在陣列中顯示未初始化的索引。但是,當您同時檢trees[3] === undefined入兩個瀏覽器時,您將得到類似的輸出true

注意:請記住,您不需要檢查陣列的未初始化索引 trees[3] === 'undefined × 1',因為它會給您一個錯誤。'undefined × 1'只是在Chrome中顯示陣列未初始化索引的方法。

問題13

下面程式碼的輸出是什麼?

var trees = ["xyz","xxxx","test","ryan","apple"];
delete trees[3];
  
  console.log(trees.length);

輸出將是5。當我們使用delete運算子刪除陣列元素時,陣列長度不受此影響。即使您使用delete運算子刪除了陣列的所有元素,這也成立。

換句話說,當delete運算子刪除陣列元素時,該陣列中不再存在該已刪除元素。代替值在刪除的索引undefined x 1undefined被放置在索引處。如果您在Chrome和Firefox中console.log(trees)輸出。["xyz", "xxxx", "test", undefined × 1, "apple"]["xyz", "xxxx", "test", undefined, "apple"]

問題14

下面程式碼的輸出是什麼?

var bar = true;
console.log(bar + 0);   
console.log(bar + "xyz");  
console.log(bar + true);  
console.log(bar + false);   

程式碼將輸出1, "truexyz", 2, 1。以下是新增運算子的一般準則:

  • 數字+數字 - >加法
  • 布林+數字 - >加法
  • 布林+數字 - >加法
  • 數字+字串 - >連線
  • String + Boolean - > Concatenation
  • String + String - > Concatenation

問題15

下面程式碼的輸出是什麼?

var z = 1, y = z = typeof y;
console.log(y);  

輸出將是undefined。根據associativity規則,具有相同優先順序的運算子基於運算子的關聯屬性進行處理。在這裡,賦值運算子的結合性Right to Left,所以typeof y會先評估,這是undefined。它將被分配給z,然後y將被賦值為z,然後z將賦值1

問題16

下面程式碼的輸出是什麼?

// NFE (Named Function Expression 
var foo = function bar(){ return 12; };
typeof bar();  

輸出將是Reference Error。要使上面的程式碼工作,您可以按如下方式重寫它:

樣品1

var bar = function(){ return 12; };
typeof bar();  

要麼

樣本2

function bar(){ return 12; };
typeof bar();  

函式定義只能有一個引用變數作為其函式名。在示例1中bar的引用變數指向anonymous function。在示例2中,函式的定義是名稱函式。

var foo = function bar(){ 
    // foo is visible here 
    // bar is visible here
 	console.log(typeof bar()); // Work here :)
 };
// foo is visible here
// bar is undefined here

問題17

下面的函式宣告有什麼區別?

var foo = function(){ 
    // Some code
}; 
function bar(){ 
    // Some code
}; 

主要區別在於foo定義了函式,run-time而函式bar是在解析時定義的。為了更好地理解這一點,讓我們看看下面的程式碼:

Run-Time function declaration 
<script>
foo(); // Calling foo function here will give an Error
  var foo = function(){ 
    console.log("Hi I am inside Foo");
 }; 
 </script>
<script>
Parse-Time function declaration 
bar(); // Calling foo function will not give an Error
 function bar(){ 
  console.log("Hi I am inside Foo");
 }; 
</script>

這種第一種宣告方式的另一個優點是您可以根據特定條件宣告函式。例如:

<script>
if(testCondition) {// If testCondition is true then 
   var foo = function(){ 
    console.log("inside Foo with testCondition True value");
   }; 
 }else{
 	 var foo = function(){ 
    console.log("inside Foo with testCondition false value");
   }; 
}
</script>

但是,如果您嘗試使用以下格式執行類似的程式碼,則會出現錯誤:

<script>
if(testCondition) {// If testCondition is true then 
   function foo(){ 
    console.log("inside Foo with testCondition True value");
   }; 
 }else{
 	 function foo(){ 
    console.log("inside Foo with testCondition false value");
   }; 
}
</script>

問題18

什麼是JavaScript中的函式提升?

功能表達

var foo = function foo(){ 
 	return 12; 
}; 

在JavaScript中,變數和函式是hoisted。讓我們hoisting先把功能。基本上,JavaScript直譯器會向前查詢所有變數宣告,然後將它們提升到宣告它們的函式的頂部。例如:

foo(); // Here foo is still undefined 
var foo = function foo(){ 
 	return 12; 
}; 

在上面的程式碼的場景後面看起來像這樣:

var foo = undefined;
    foo(); // Here foo is undefined 
 	   foo = function foo(){
 	      / Some code stuff
      }
var foo = undefined;
 	 foo = function foo(){
 	     / Some code stuff
    }
    foo(); // Now foo is defined here

問題19

下面的程式碼輸出是什麼?

var salary = "1000$";

 (function () {
     console.log("Original salary was " + salary);

     var salary = "5000$";

     console.log("My New Salary " + salary);
})();

輸出將是undefined, 5000$。新手常常被JavaScript的提升概念所欺騙。在上面的程式碼中,您可能希望salary從外部作用域保留其值,直到salary在內部作用域中重新宣告的點。但是,由於hoisting,工資價值是undefined相反的。要更好地理解這一點,請檢視以下程式碼:

var salary = "1000$";

(function () {
    var salary = undefined;
    console.log("Original salary was " + salary);

    salary = "5000$";

    console.log("My New Salary " + salary);
})();

salary變數在函式範圍的頂部被提升並宣告。該console.log內部回報率undefined。之後console.logsalary重新申報並分配5000$

問題20

instanceofJavaScript中的運算子是什麼?下面程式碼的輸出是什麼?

function foo(){ 
  return foo; 
}
new foo() instanceof foo;

這裡,instanceof運算子檢查當前物件,如果物件是指定型別,則返回true。

例如:

var dog = new Animal();
dog instanceof Animal // Output : true

dog instanceof Animal是真的,因為dog繼承自Animal.prototype

var name = new String("xyz");
name instanceof String // Output : true

name instanceof String是真的,因為dog繼承自String.prototype。現在讓我們理解下面的程式碼:

function foo(){ 
  return foo; 
}
new foo() instanceof foo;

這裡函式foo返回foo,再次指向函式foo

function foo(){
  return foo; 
}
var bar = new foo();
// here bar is pointer to function foo(){return foo}.

所以new foo() instanceof foo迴歸false;

參考連結

問題21

如果我們有一個JavaScript關聯陣列

var counterArray = {
    A : 3,
  	B : 4
};
counterArray["C"] = 1;

我們如何計算上述關聯陣列的長度counterArray

此處沒有可用於計算關聯陣列物件長度的內建函式和屬性。但是,我們可以通過其他方式計算關聯陣列物件的長度。除此之外,我們還可以Object通過向原型新增方法或屬性來擴充套件,以便計算長度。但是,擴充套件物件可能會破壞各種庫中的列舉,或者可能會產生跨瀏覽器問題,因此除非必要,否則不建議使用它。同樣,我們可以通過各種方式計算長度。

Objectkeys可用於計算物件長度的方法:


We can also calculate the length of an object by iterating through an object and by counting the object's own property.  

```javascript
function getSize(object){
  var count = 0;
  for(key in object){
    // hasOwnProperty method check own property of object
    if(object.hasOwnProperty(key)) count++;
  }
  return count;
}
我們還可以length直接新增方法Object
Object.length = function(){
  	var count = 0;
  for(key in object){
    // hasOwnProperty method check own property of object
    if(object.hasOwnProperty(key)) count++;
  }
  return count;
}
//Get the size of any object using
console.log(Object.length(counterArray))

另外的方式:我們也可以使用Underscore(推薦,因為它的重量輕)來計算物件長度。

本文翻譯自:點選訪問