前端20道面試題你會
問題1:JavaScript 中 undefined 和 not defined 的區別
JavaScript 未宣告變數直接使用會丟擲異常:var name is not defined,如果沒有處理異常,程式碼就停止運行了。
但是,使用typeof undeclared_variable並不會產生異常,會直接返回 undefined。
varx;// 宣告 xconsole.log(x);//output: undefined
console.log(typeof y); //output: undefined
console.log(z); // 丟擲異常: ReferenceError: z is not defined
問題2:下面的程式碼輸出什麼?
vary =1;if(functionf(){}) { y +=typeoff;}console.log(y);
正確的答案應該是 1undefined。
JavaScript中if語句求值其實使用eval函式,eval(function f(){}) 返回 function f(){} 也就是 true。
下面我們可以把程式碼改造下,變成其等效程式碼。
vark =1;if(1) {eval(functionfoo(){}); k +=typeoffoo;}console.log(k);
上面的程式碼輸出其實就是 1undefined。為什麼那?我們檢視下 eval() 說明文件即可獲得答案
該方法只接受原始字串作為引數,如果 string 引數不是原始字串,那麼該方法將不作任何改變地返回。
恰恰 function f(){} 語句的返回值是 undefined,所以一切都說通了。
注意上面程式碼和以下程式碼不同。
vark =1;if(1) {functionfoo(){}; k +=typeoffoo;}console.log(k);// output 1function
問題3:在JavaScript中建立一個真正的private方法有什麼缺點?
每一個物件都會建立一個private方法的方法,這樣很耗費記憶體
觀察下面程式碼
varEmployee =function(name, company, salary){this.name = name ||"";this.company = company ||"";this.salary = salary ||5000;// Private methodvarincreaseSalary =function(){this.salary =this.salary +1000; };// Public methodthis.dispalyIncreasedSalary =function(){ increaseSlary();console.log(this.salary); };};// Create Employee class objectvaremp1 =newEmployee("John","Pluto",3000);// Create Employee class objectvaremp2 =newEmployee("Merry","Pluto",2000);// Create Employee class objectvaremp3 =newEmployee("Ren","Pluto",2500);
在這裡 emp1,emp2,emp3都有一個increaseSalary私有方法的副本。
所以我們除非必要,非常不推薦使用私有方法。
問題4:JavaScript中什麼是閉包?寫出一個例子
老生常談的問題了,閉包是在一個函式裡聲明瞭另外一個函式,並且這個函式訪問了父函式作用域裡的變數。
下面給出一個閉包例子,它訪問了三個域的變數
它自己作用域的變數
父函式作用域的變數
全域性作用域的變數
varglobalVar ="abc";// Parent self invoking function (functionouterFunction(outerArg){// begin of scope outerFunction// Variable declared in outerFunction function scope varouterFuncVar ='x';// Closure self-invoking function (functioninnerFunction(innerArg){// begin of scope innerFunction// variable declared in innerFunction function scopevarinnerFuncVar ="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 is closure that is defined inside outerFunc
輸出很簡單:
outerArg=7outerFuncVar= xinnerArg=5innerFuncVar= yglobalVar= abc
問題5:寫一個mul函式,使用方法如下。
console.log(mul(2)(3)(4));// output : 24 console.log(mul(4)(3)(4));// output : 48
答案直接給出:
functionmul(x){returnfunction(y){// anonymous function returnfunction(z){// anonymous function returnx * y * z; }; };}
簡單說明下: mul 返回一個匿名函式,執行這個匿名函式又返回一個匿名函式,最裡面的匿名函式可以訪問 x,y,z 進而算出乘積返回即可。
對於JavaScript中的函式一般可以考察如下知識點:
函式是一等公民
函式可以有屬性,並且能連線到它的構造方法
函式可以像一個變數一樣存在記憶體中
函式可以當做引數傳給其他函式
函式可以返回其他函式
問題6:JavaScript怎麼清空陣列?
如
var arrayList = ['a','b','c','d','e','f'];
怎麼清空 arrayList
方法1
arrayList = [];
直接改變arrayList所指向的物件,原物件並不改變。
方法2
arrayList.length = 0;
這種方法通過設定length=0 使原陣列清除元素。
方法3
arrayList.splice(0, arrayList.length);
和方法2相似
問題7:怎麼判斷一個object是否是陣列(array)?
方法1
使用 Object.prototype.toString 來判斷是否是陣列
functionisArray(obj){returnObject.prototype.toString.call( obj ) ==='[object Array]';}
這裡使用call來使 toString 中 this 指向 obj。進而完成判斷
方法二
使用 原型鏈 來完成判斷
functionisArray(obj){returnobj.__proto__ ===Array.prototype;}
基本思想是利用 例項如果是某個建構函式構造出來的那麼 它的 __proto__是指向建構函式的 prototype屬性。
方法3
利用JQuery
functionisArray(obj){return$.isArray(obj)}
JQuery isArray 的實現其實就是方法1
問題8:下面程式碼輸出什麼?
varoutput = (function(x){deletex;returnx;})(0);console.log(output);
輸出是 0。 delete 操作符是將object的屬性刪去的操作。但是這裡的 x 是並不是物件的屬性, delete 操作符並不能作用。
問題9:下面程式碼輸出什麼?
varx =1;varoutput = (function(){deletex;returnx;})();console.log(output);
輸出是 1。delete 操作符是將object的屬性刪去的操作。但是這裡的 x 是並不是物件的屬性, delete 操作符並不能作用。
問題10:下面程式碼輸出什麼?
varx = {foo:1};varoutput = (function(){deletex.foo;returnx.foo;})();console.log(output);
輸出是 undefined。x雖然是全域性變數,但是它是一個object。delete作用在x.foo上,成功的將x.foo刪去。所以返回undefined
問題11:下面程式碼輸出什麼?
varEmployee = {company:'xyz'}varemp1 =Object.create(Employee);deleteemp1.companyconsole.log(emp1.company);
輸出是 xyz,這裡的 emp1 通過 prototype 繼承了 Employee的 company。emp1自己並沒有company屬性。所以delete操作符的作用是無效的。
問題12:什麼是 undefined x 1 ?
在chrome下執行如下程式碼,我們就可以看到undefined x 1的身影。
vartrees = ["redwood","bay","cedar","oak","maple"];deletetrees[3];console.log(trees);
當我們使用 delete 操作符刪除一個數組中的元素,這個元素的位置就會變成一個佔位符。打印出來就是undefined x 1。
注意如果我們使用trees[3] === 'undefined × 1'返回的是 false。因為它僅僅是一種打印表示,並不是值變為undefined x 1。
問題13:下面程式碼輸出什麼?
vartrees = ["xyz","xxxx","test","ryan","apple"];deletetrees[3];console.log(trees.length);
輸出是5。因為delete操作符並不是影響陣列的長度。
問題14:下面程式碼輸出什麼?
varbar =true;console.log(bar +0);console.log(bar +"xyz");console.log(bar +true);console.log(bar +false);
輸出是
1
truexyz
2
1
下面給出一個加法操作表
Number + Number -> 加法
Boolean + Number -> 加法
Boolean + Boolean -> 加法
Number + String -> 連線
String + Boolean -> 連線
String + String -> 連線
問題15:下面程式碼輸出什麼?
varz =1, y = z =typeofy;console.log(y);
輸出是 undefined。js中賦值操作結合律是右至左的 ,即從最右邊開始計算值賦值給左邊的變數。
上面程式碼等價於
varz =1z =typeofy;vary = z;console.log(y);
問題16:下面程式碼輸出什麼?
varfoo =functionbar(){return12; };typeofbar();
輸出是丟擲異常,bar is not defined。
如果想讓程式碼正常執行,需要這樣修改程式碼:
varbar =function(){return12; };typeofbar();
或者是
functionbar(){return12; };typeofbar();
明確說明這個下問題
varfoo =functionbar(){// foo is visible here // bar is visible hereconsole.log(typeofbar());// Work here :)};// foo is visible here// bar is undefined here
問題17:兩種函式宣告有什麼區別?
varfoo =function(){// Some code};functionbar(){// Some code};
foo的定義是在執行時。想系統說明這個問題,我們要引入變數提升的這一概念。
我們可以執行下如下程式碼看看結果。
console.log(foo)console.log(bar)varfoo =function(){// Some code};functionbar(){// Some code};
輸出為
undefinedfunctionbar(){// Some code};
為什麼那?為什麼 foo 打印出來是 undefined,而 bar打印出來卻是函式?
JavaScript在執行時,會將變數提升。
所以上面程式碼JavaScript 引擎在實際執行時按這個順序執行。
// foo bar的定義位置被提升functionbar(){// Some code};varfoo;console.log(foo)console.log(bar)foo =function(){// Some code};
原始碼的輸出合理解釋了。
問題18:下面程式碼輸出什麼?
varsalary ="1000$";(function(){console.log("Original salary was "+ salary);varsalary ="5000$";console.log("My New Salary "+ salary);})();
輸出是
Originalsalary was undefinedMyNew Salary 5000$
這題同樣考察的是變數提升。等價於以下程式碼
varsalary ="1000$"; (function(){varsalary ;console.log("Original salary was "+ salary); salary ="5000$";console.log("My New Salary "+ salary); })();
問題19:什麼是 instanceof 操作符?下面程式碼輸出什麼?
functionfoo(){returnfoo; }console.log(newfoo()instanceoffoo);
instanceof操作符用來判斷是否當前物件是特定類的物件。
如
functionAnimal(){//或者不寫return語句returnthis;}vardog =newAnimal();doginstanceofAnimal// Output : true
但是,這裡的foo定義為
functionfoo(){returnfoo; }
所以
// here bar is pointer to function foo(){return foo}.varbar =newfoo();
所以 new foo() instanceof foo 返回 false
問題20: 如果我們使用JavaScript的"關聯陣列",我們怎麼計算"關聯陣列"的長度?
varcounterArray = {A:3,B:4};counterArray["C"] =1;
其實答案很簡單,直接計算key的數量就可以了。
Object.keys(counterArray).length // Output 3
本文給出的面試題答案只是很多合理答案中的幾個,可能會不全面,歡迎大家補充。由於個人疏忽等原因,本文中難免會存在少量錯誤,歡迎大家批評指正。