JavaScript經典筆試題

b10l07發表於2018-12-04

1.下面程式的執行結果是(函式引數,Arguments 物件)

function test(x, y, z) {  
  alert(test.length);
  alert(arguments.length);
  alert(arguments.callee === test);
  alert(arguments[2]);
}
test(10, 20);

A.2,3,true,0 B.3,3,false,20 C.3,2,true,undefined D.2,3,false,10
分析:test.length是返回的函式的形參個數,所以為3;arguments.length返回的是函式呼叫時的實參個數,所以為2;arguments.callee:初始值就是正被執行的 Function 物件,用於在函式內部呼叫自身,特別是函式本身為匿名函式時,要在內部呼叫自己,那麼它就閃亮登場了,arguments物件本身是個由函式呼叫時傳入的實參組成的偽陣列,訪問單個引數的方式與訪問陣列元素的方式相同。索引 n 實際上是 arguments 物件的 0…n 屬性的其中一個引數。由於呼叫test時,沒有傳入第三個引數,所以返回undefined
擴充套件:談到arguments,在說說它的另一個應用,剛才談到arguments.length返回的是函式呼叫時的實參個數,那麼通過判斷這個實參個數,我們就可以優雅的模擬實現js的”過載“了

function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 5);
  } else if(arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

doAdd(10); //輸出 "15"
doAdd(40, 20); //輸出 "60"
當只有一個引數時,doAdd() 函式給引數加 5。如果有兩個引數,則會把兩個引數相加,返回它們的和。所以,doAdd(10) 輸出的是 "15",而 doAdd(40, 20) 輸出的是 "60"。雖然不如過載那麼好,不過已足以避開 ECMAScript 的這種限制。

  1. 下面程式的執行結果是(作用域,變數提升)
var x = 30;
function test(){
    alert(x);
    var x = 10;
    alert(x);
    x = 20;
    function x() {};
    alert(x);
}
test();

A.30,10,function x(){} B.undefined,10,20 C. function x(){},10,20 D. 30,10,20
分析:進入test函式,第一個alert(x)返回的是function x(){},為什麼了?這個就要從js的預解析談起了,進入函式的作用越後,js會首先讀取變數和函式的宣告,當變數和函式重名時(不管誰先誰後),函式名優先(具體的原因,我將稍後單獨寫一篇隨筆)所以這個地方x指向了function x(){}。為什麼不是外面的x=30了?因為在test函式的作用域裡,能夠找到x的宣告,所以相當於內部x將外部的x給遮蔽了!執行第二個alert(x)時,前面一行已經給x賦值為10,所以為10;執行第三個alert(x)時,變數x已經被賦值為20了,那麼function x(){}對x有什麼影響了?沒有任何影響,因為它就僅僅是個函式宣告。所以為20

  1. 下面程式的執行結果是(閉包)
 function test() {
    var x = 10;
    var y = 20;
    return function () {
        alert([x, y]);
    };
}
var x = 30;
var y = 40;
var temp = test();
temp(); 

A.30,40 B.10,40 C.10,20 D.30,20
分析: 顯示,通過temp此時已經是一個函式了,它相當於 temp = function(){ alert([x,y])}。此時關鍵是看x,y的值了,到底是指向test函式裡裡面的值了還是外面。
此處又涉及到了 閉包,即test內部的x,y沒有釋放,原因就是alert([x,y])引用了它,所以答案是 C

  1. 1), 2) ,3)的執行結果分別是(運算子)
  1. false == 0
  2. "5" + 3
    3)"5" + {
    toString: function(){return this;},
    valueOf: function(){return "valueOf";}
    }
    A.true,"8","5this" B.false,8,"5valueOf"
    C.true,"53","5valueOf" D.fasle,"53","5[object Objetc]"
    分析:1中為true,因為==會執行一個型別自動轉化,Number(false)的值為0,Boolean(0)的值為false;
    2,“+”此時是做為連結符號存在的。ECMAScript262中規定,首先對"+"前後的兩個表示式進行求值,即呼叫valueof方法。再呼叫typeof對他們的型別進行判斷,如果有一個型別為string的則都將轉化為string。所以後面的3會被轉化為string型別。如果此處為“-”,則答案為2,會將前面的“5”轉化為number型別
    3,在2中已經說到,“+”後面的物件,首先會呼叫valueOf(),所以後面的物件的求值結果為“valueOf”,也是字串。最後直接連線在一起。
    5.下面輸出的值是多少?(考察this)
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應該沒有問題。我們知道取物件屬於除了點操作符還可以用中括號,所以第二次執行時相當於arguments呼叫方法,this指向arguments,而這裡傳了兩個引數,故輸出arguments長度為2。
6.以下輸出結果是多少?(var和函式的提前宣告)

function fn(a) {
  console.log(a); 
  var a = 2;
  function a() {}
  console.log(a); 
}
fn(1);

輸出:function a() {} 2
我們知道var和function是會提前宣告的,而且function是優先於var宣告的(如果同時存在的話),所以提前宣告後輸出的a是個function,然後程式碼往下執行a進行重新賦值了,故第二次輸出是2。
7.以下輸出結果是?(區域性變數和全域性變數)

var f = true;
if (f === true) {
  var a = 10;
}
function fn() {
  var b = 20;
  c = 30;
}
fn();
console.log(a);
console.log(b);
console.log(c);

輸出:10 報錯 30  
{...}內的新宣告的變數不是區域性變數(var 宣告 let不成立,因為let有程式碼塊域的存在),function內的新宣告的變數才是區域性變數,而沒有用var宣告的變數在哪裡都是全域性變數。再次提醒切記只有function(){}內新宣告的才能是區域性變數,while{...}、if{...}、for(..) 之內的都是全域性變數(除非本身包含在function內)

相關文章