分享:JavaScript常見面試題
JavaScript
1.1 簡要描述JavaScript的資料型別?
JavaScript的資料型別可以分為原始型別和物件型別。
原始型別包括string、number和boolean三種。其中,字串時使用一對單引號或者一對雙引號括起來的任意文字;而數字型別都採用64位浮點格式儲存,不區分整數和小數;布林(邏輯)型別只能有兩個值:true或false。
複雜型別指其他物件,如Array、Date、Object等。
除此之外,JavaScript中海油兩個特殊的原始值: null(空)和undefined(未定義),它們代表了各自特殊型別的唯一成員。
1.2 讀程式碼,寫結果
寫出下列表達式的計算結果: 上述程式碼的結果分別為:
var a=[];
var b=a;
b[0]=1;
console.log(a[0]); 1
console.log(b[0]); 1
console.log(a===b); true
將物件賦值給變數,僅僅數賦值的引用,物件本身並沒有賦值一次,因此,變數a和變數b指向同一個陣列。
1.3 簡要描述null和undefined的區別
null :是JavaScript的關鍵字,用於描述”空值”,對其執行typeof操作,返回”object”,即為一個特殊的物件值,可以表示數字、字串和物件時”無值”的。
undefined :是預定義的全域性變數,其值為”未定義”,它是變數的一種取值,表示變數沒有初始化。當查詢物件屬性、陣列元素的值時,如果返回undefined則表示屬性或者元素不存在;如果函式沒有任何返回值,也返回undefined。
需要注意的是,雖然null和undefined是不同的,但是因為都表示”值的空缺”,兩者可以互換。因此,使用”==”任務二者是相等的,需要使用”===”來區分它們。
1.4 讀程式碼,寫結果
寫出下列表達式的計算結果: 上述程式碼的結果分別為:
10+”object”10object //轉換為字串
“7” * ”4”28 //轉換為字元
1 - ”x”
1 + { }1[object object] //返回物件的toString()結果按照字串相加
true + true2 //bool型別轉換為數字型別
2 + null2//null轉換為數值0
1.5 讀程式碼,寫結果
寫出下列表達式的計算結果: 上述程式碼的結果分別為:
var a=2;
var obj={x:1,y:{z:2}};
Var n=[obj,3,[4,5]];
console.log(a<<2);8
console.log(obj[“y”].z);2
console.log(n[0].y[“z”]);2
console.log(n[2][“1”]);5
delete n[0];console.log(n[0].x);此行程式碼錯誤輸出Error
1.6 閱讀如下程式碼:
var x=10;
var y=20;
var z=x<y?x++:++y;
上述程式碼執行後,變數x、y、z的值是多少?
答案:上述程式碼執行後,變數想x的值為11;變數y的值為20;變數z的值為10。
這是因為,執行第三行程式碼時,只執行?後的第一個語句,因此,y的值不發生變化,仍為20;並返回x的值賦值給變數z,因此z的值為10,然後將x的值增加1,變為11。
1.7 什麼是”邏輯短路”?
邏輯短路時對於邏輯運算而言,是指僅計算邏輯表示式中的一部分便能缺點結果,而不對整個表示式進行計算的現象。
對於”&&”運算子,當第一個運算元為false時,將不會判斷第二個運算元,吧、因為此時無論第二個運算元為何,最後的運算結果一定是false;
對於” || ”運算子,當第一個運算元為true時,將不會判斷第二個運算元,因為此時無論第二個運算元為何,最後的運算結果一定是true。
1.8 閱讀如下程式碼
var empAge=20;
var empName;
if(empAge>20&&empName.length>0){
console.log(1);
}else{
console.log(2);
}
上述程式碼執行後,將產生有效輸出,還是程式碼錯誤?
參考答案:上述程式碼執行,會輸出2,而不會發生錯誤。
這是因為,if條件中的邏輯表示式的第一個條件(empAge>20)不滿足,會返回false,此時將發生邏輯短路,而不會繼續判斷下一個條件。因此,即使下一個條件中的變數empName沒有賦值,此時如果計算empName.length將發生錯誤;但是,因為發生了邏輯短路,不會計算此表示式,因此不會發生錯誤。
既然if條件中的邏輯表示式返回false,則執行else語句:輸出2。
1.9 解釋一下JavaScript中的區域性變數與全域性變數區別
全域性變數擁有全域性作用域,在JavaScript程式碼的任何地方都可以訪問;在函式內宣告的變數只是在函式體內有定義,即為區域性變數,其作用域是區域性性的。
需要注意的是,在函式體內宣告區域性變數時,如果不使用var關鍵字,則將宣告全域性變數。
1.10 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var x=”global”;
function test(){
var x=”local”;
return x;
}
console.log(test());
參考答案:上述程式碼的輸出結果為local。這是因為,在函式test()體內,區域性變數的優先順序高於同名的全域性變數。因此,如果在函式體內宣告的區域性變數和全域性變數重名,則以區域性變數優先。因此,呼叫函式test()時,返回的是區域性變數x,其值為local。
1.11 什麼是JavaScript中的函式作用域
JavaScript中的函式作用域是指:變數在宣告它的函式體以及這個函式體巢狀的任意函式體內都有定義的。這意味著,在函式體內宣告的所有變數在整個函式體內始終是可見的,這種特性也被稱為“宣告提前”,即函式內宣告的所有變數(不涉及到賦值)都被提前至函式的頂部宣告。
比如,檢視如下程式碼:
function test(){
console.log(x);
var x=10;
console.log(x);
}
test();
上訴程式碼執行,將先輸出undefined,再輸出10.
這是因為,雖然變數x在第二行宣告並賦值,丹其有效範圍為整個函式體,因此,第一行程式碼輸出時,表示變數x已經宣告但是沒有賦值,因此輸出undefined;第三行程式碼執行時,因為變數x已經賦值為10,則輸出10。
1.12 讀程式碼,寫結果
寫出下列程式碼的輸出結果
function test(){
var sum=0;
for(var i=0;i<10;i++){
sum+=i;
}
console.log(sum);
console.log(i);
}
test();
上述程式碼中,輸出sum的值為45;輸出i的值為10。
這是因為,在函式test()體內,迴圈計算完畢後,變數sum的值從0累加到10的和即為45;變數i雖然是在for迴圈中宣告,但是在整個函式體內都有效(函式左右域),因此,迴圈完畢後,變數i的值為10。
1.13 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var x=”global”;
function test(){
console.log(x);
var x=”local”;
console.log(x);
}
test();
上述程式碼中,先輸出undefined,再輸出local。
函式test()體內聲明瞭與全域性變數同名的區域性變數x,則將覆蓋全域性變數,即區域性變數優先。因此,第一次輸出變數x時,為輸出區域性變數x,此時變數x只有宣告而沒有賦值,因此輸出undefined;第二次輸出變數x時,區域性變數x已經賦值,因此輸出字串local。
1.14 簡述arguments物件的作用
在函式程式碼中,使用特殊物件arguments可以訪問函式的引數。即開發者在定義函式時,無需明確的為方法宣告引數,也可以在方法體中使用arguments來訪問引數。這是因為,arguments是一種特殊物件,在函式程式碼中,表示函式的引數陣列。
正因為arguments表示引數組成的陣列,因此,首先可以使用arguments.length檢測函式的引數個數,其次,可以通過下標(arguments[index])來訪問某個引數。這樣可以用arguments物件判斷傳遞給函式的引數個數並獲取引數,適用於函式引數無法確定個數的情況下。
1.15 簡要描述JavaScript中定義函式的幾種方式
JavaScript中,有三種定義函式的方式:
函式語句:即使用function關鍵字顯示定義函式。如:
function f(x){return x+1;}
函式定義表示式:也稱為“函式直接量”。如:
Var f=function(x){return x+1;}
使用Function()建構函式定義。如:
var f=new Function(“x”,”return x+1;”);
1.16 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var f=function (x) {return x*x;}
console.log(f);
console.log(f(10));
上述程式碼執行時,先輸出function(x) {return x*x;};再輸出100。
這是因為,變數f代表一個函式物件,因此直接輸出變數時,將輸出函式體對應的字元文字;f(10)表示呼叫變數f所對應的函式,返回100並輸出。
1.17 閱讀如下程式碼
function f(){
console.log(“function”);
}
function test(){
console.log(f);
f();
f=”hello”;
console,log(f);
f();
}
test();
上述程式碼執行,會先輸出:function f(){console.log("function");};然後輸出function;再輸出hello;然後會輸出異常資訊:string is not a function。
這是因為,定義函式時,函式名稱作為一個全域性變數,該變數指向函式物件。因此,執行函式test中的第一行程式碼時,將輸出變數f所對應的函式物件,即輸出函式體中程式碼的字串形式;然後執行f()表示呼叫方法f,則輸出字串”function”;執行程式碼f=”hello”,意味著將變數f的值改為字串,因此再輸出變數f時,將輸出字串”hello”;而如果試圖再執行f(),會引發錯誤。這是因為,此時,變數f不再是一個函式物件,而是一個普通字串。
1.18 列舉幾個JavaScript中常用的全域性函式,並描述其作用
JavaScript中常用的全域性函式及作用如下:
parseInt:解析一個字串並返回一個整數;
parseFloat:解析一個字串並返回一個浮點數;
isNaN:檢查某個值是否是數字,返回true或者false;
encodeURI:把字串作為URI進行編碼;
decodeURI:對encodeURI()函式編碼過的URI進行解碼;
eval:計算某個字串,以得到結果,或者用於執行其中的JavaScript程式碼。
1.19 閱讀如下程式碼
function printArray(arr){
for(var i in arr){
if(arr[i] instanceof Array){
printArray(arr[i]);
}else{
document.write(arr[i]+’‘);
}
}
}
var data=[1,[20,32],[[301,302],[310,311]]];
printArray(data);
上述程式碼執行後,頁面是輸出:1 20 32 301 302 310 311。
函式parintArray使用了地櫃方式,逐一輸出陣列中的每個成員,中間以空格隔開。
1.20 編寫函式,實現氣泡排序
使用JavaScript便也的氣泡排序函式如下所示:
function bubbleSort(arr){
for (var i=0;i<arr.length;i++){
for(var j=0;j<arr.length;j++){
if(arr[i]>arr[j+1]){
var temp=arr[j+1];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
var arr=[12,4,9,21,43,3];
bubbleSort(arr);
console.log(arr);
上述程式碼執行時,將輸出排序後的結果:[3,4,9,12,21,43]。
1.21 編寫程式碼,實現插入排序
插入排序是指,先假定將n個元素的數列分為有序和無序兩個部分;然後將無序數列的第一個元素與有序數列的元素從後往前逐個進行比較,找出插入位置,將該元素插入到有序數列的合適位置中。過程如下圖所示:
使用JavaScript編寫的插入排序函式如下所示:
function insertionSort(arr){
for(var i=1;i<arr.length;i++){
var k=arr[i];
var j;
for(j=i-1;j>=0&&k<arr[j];j--){
arr[j+1]=arr[j];
}
arr[j+1]=k;
}
}
var arr-[12,4,9,21,43,3];
insertionSort(arr);
console.log(arr);
上述程式碼執行時,將輸出排序後的結果:[3,4,9,12,21,43]。
1.22 編寫函式,實現對身份證號碼最後一位的驗證
二代身份證號碼17位數分別乘以不同的係數。從第一位到第十七位的係數分別為:
7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2
將這17位數字和係數相乘的結果相加
用加出來和除以11,看餘數是多少?
餘數只可能有0 1 2 3 4 5 6 7 8 9 10這11個數字。每個數字所對應的最後一位身份證的號碼為1 0 x 9 8 7 6 5 4 3 2。即如果餘數是2,就會在身份證的第18位數字上出現羅馬數字的X。如果餘數是10,身份證的最後一位號碼就是2。
例如:某男性的身份證號碼是34052419800101001X。驗證其最後一位是否正確是,首先需要得出前17位的乘積和是189,然後用過189除以11得出的結果是17+2/11,也就是說其餘數是2.最後通過對應規則就可以知道餘數2對應的數字是x。所有,可以批判次身份證號碼的最後一位是合格的。
編寫驗證方法如下:
function verifyCode(id){
if(id.length!=18){return false;}
var arr=[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];
var sum=0;
for(var i=0;i<arr.length;i++){
sum+=parseInt(id.charAt(i))*arr[i];
}
var c=sum%11;
var ch=[‘1’,’0’,’x’,’9’,’8’,’7’,’6’,’5’,’4’,’3’,’2’];
var code=ch[c];
var last=id.charAt(17);
last=last==’x’?’x’:last;
return last==code;
}
var id=”34052419800101001X”;
console.log(verifyCode);
1.23 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var arr1=[10,20];
arr1.push(30);
arr1.push([40,50]);
var data=arr1.pop();
console.log(data);
上述程式碼的輸出結果為[4.,50]。
陣列的方法push()表示入棧,即在棧頂(陣列尾端)新增指定的元素;方法pop()表示出棧,刪除並返回棧頂(陣列尾端)的元素。
程式碼中,第一次入棧為數字30;第二次入棧為陣列[40,50],且該陣列排在棧頂。因此,呼叫方法pop()時,將刪除並返回棧頂元素[40,50,],這是一個數組,因此輸出結果為[40,50]。
1.24 什麼是棧?在JavaScript中,如何模擬棧操作?
棧(stack)是一種運算受限的線性表,其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱為棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成為新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成為新的棧頂元素。棧的操作如下圖所示:
在JavaScript中,可以使用陣列及其相關操作來模擬棧操作。首先,使用陣列儲存一列元素,然後使用陣列的push()方法在陣列的尾部新增指定的元素,類似於在棧頂新增元素,即頂部入;然後使用陣列的pop()刪除並返回陣列尾部的元素,類似於頂部出棧,即後入的元素先出。
1.25 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var arr1=[10,20,30,40];
arr1.push(50);
arr1.shift();
console.log(arr1);
上述程式碼的輸出結果為[20,30,40,50]。
陣列的方法push()表示入棧,即在棧頂(陣列尾端)新增指定的元素,因此,數字50將作為陣列的最後一個元素;方法shift()表示刪除並返回棧底(陣列頭部)的元素,因此,將從陣列刪除數值10.此時,輸出陣列,將輸出剩餘的4個數值,即[20,30,40,50]。
1.26 什麼是正則表示式?在JavaScript中,如何讓應用z正則表示式?
正則表示式本身就是一個字串,由一些普通字元和特殊字元組成的,用以描述一種特定的字元規則的表示式。
正則表示式常用於在一段文字中搜索、匹配或替換特定形式的文字。如:詞語出現頻率統計、驗證字串是否符合郵箱格式、遮蔽一片帖子中的限制性詞語等。許多程式設計語言都支援利用正則表示式進行字串操作。
在JavaScript中,正則表示式的應用分為兩種:
1.結合string物件的replace、search和match()方法,實現對字串的替換、查詢和匹配;
2.定義正則表示式物件,實現對字串的複雜匹配操作。
1.27 讀程式碼,寫結果
寫出下列程式碼的輸出結果:
var regxp=/\bdo\b/ig;
var data=’he does told to Do do.’;
console.log(data.search(regexp));
上述程式碼的輸出結果為3。
String 的search(regexp)方法,用於返回第一次出現匹配指定正則表示式的下標,若沒有匹配則返回-1.
程式碼中,正則表示式式\bdo\b表示匹配完整的單詞do,且不區分大小寫。而變數data中,第一次出現單詞do(不區分大小寫)的位置是16。
1.28 閱讀如下程式碼
function add(num) {
try {
num = Number(num);
if (isNaN(num)) {
throw new Error('Arguments is NaN');