一些js小題,掌握這些對於一些常見的面試、筆試題應該很有幫助:
var a=10;
function aa(){
alert(a);
}
function bb(){
aa();
}
bb();//10 因爲bb函數調用aa時,程序在執行aa,執行aa時只能找到全局中的a:10
當函數中聲明變量不加var時則爲全局變量:
function test(){
var a=b=10;
}
test(); //切記:一定要執行
alert(b);//全局 10
alert(a);//報錯,因爲定義在函數內部,有var,屬於函數內的變量,外部無法訪問
優先使用內部的變量,沒有再往上查找,直到找到window,若還沒有則出錯,說明變量沒有聲明,如下:
var a=10;
function aa(){
var a=20;
alert(a);
}
aa();//20 優先使用自身定義的var a=20,而不用再往上搜索全局
但倘若把var a=20;放到alert(a);之後,則會undefined,例如下面代碼:
var a=10;
function aa(){
alert(a);
var a=20;//放在了alert(a);之後
}
aa(); //undefined
這個問題之前也讓我百思不得其解,現在我終於懂了,函數在讀取變量時有個“預加載”特性。之所以彈出undefined很明顯是沒找到,爲什麼沒找到呢?原來是函數執行時已經知道函數內部已經定義了var a;了,這時就不會再往上查找全局(把後路堵死了),但當執行到alert(a);時 還有沒執行到var a=20;也就是說此時的a還沒有被賦值,所以爆出undefined。總結就是:只要聲明瞭var a=20;無論位置在哪,都不會再往上查找,還沒來得及賦值就被alert了。代碼就相當於:
var a=10;
function aa(){
var a; //已經聲明有a就不會再往上查找
alert(a);//執行時還未聲明
a=20; //賦值已經晚了。已經爆出undefined了!
}
aa();//undefined
那如果把函數內部的var a=10;的var 去掉呢?請看代碼?
var a=10;
function test(){
a=20; //去掉了var,a也變爲全局
alert(a);
}
test(); //20
很明顯結果是20,給人的錯覺是直接使用了內部的a=20,其實這樣理解是錯的,因爲沒有var,a變爲全局,對函數來說內部是沒有a的,會向上查找a,很高興的找到了var a=10;沒錯,剛找到時依然爲10,然後把a的值也就是10帶入函數內部後,發現:尼瑪!函數裏有a=20;這條代碼,就這樣丟掉a的原值10,重新使用20,這樣再被彈出。於是乎我們就看到了20,這個20可不是直接從內部拿來用的,而是從外面溜了一圈後才使用的20。內部環境可使用外部的變量,外部變量不能使用內部的:
var a=10;
function aa(){
function bb(){
var a=20;
alert(a);//此處負責彈出bb自己本身的a :20
}
bb();
alert(a);//此處負責彈出全局中的10
}
aa(); //先彈出20,再彈出10
(function f(){
function f(){alert('1');}
return f(); //函數聲明有提前執行的作用,也就是在return(雖然return後面的代碼不執行)
function f(){alert('2');}
function f(){alert('3');}
function f(){alert('4');}//函數聲明提前執行,f()已經被一次次更新
alert('sss');//永遠不會執行因爲在return後的代碼不執行(匿名函數除外)
})() //4
以上代碼執行結果爲4,因爲前面的函數都被最後一個重寫(函數名一樣),且在return之前執行,但最後一句alert('sss');永遠不會執行,因爲它沒有像函數聲明一樣的提前執行待遇,並且位置處在return後面,被無情的拋棄,永遠不會執行。
關於引用型數據:
先來了非引用數據吧:
var a=1;
var b=a;
b++; //更改b 加1
alert(b); //2 彈出更改後的b
alert(a);//1 不變,也就是說b的改變不影響a
但引用型數據就不行了:
var a=[1,2,3];
var b=a;
b.push(4); //修改b
alert(b);//1234 改變
alert(a);//1234 也改變,說明兩者共同使用一個引用,共同指向一個內存區域,一個修改,另一個也跟着改
上面代碼只是修改b,那如果對b重新賦值呢?
var a=[1,2,3];
var b=a;
b=[4,5,6];
alert(b);//456
alert(a);//123 不變
隨着b的重新複製,那麼就切斷了引用,另立門戶,和a再也沒有任何關係。當全局變量以參數的方式傳進函數內部後,在內部對變量的操作就不再影響外部的全局,但引用同樣不符合這條規則。
先來段非引用:
var a=10;
function test(a){
a=a+3;
alert(a);// 負責彈出傳進函數內部且被修改後的a,值爲13
}
test(a); //負責彈出全局中的10,說明全局沒有被修改
alert(a); //先彈出13,後彈出10
以上原理註釋中已經說明,如果去掉傳參的方式呢?
var a=10;
function test(){
a=a+3;
alert(a);//13
}
test(a); //13
alert(a); //結果13, 13
沒有傳進參數,a就被函數內部修改(內部有權使用外部變量)。
引用型哪怕以傳參的方式依然會影響外部變量:
var a=[1,2,3]; //引用型傳進之後在函數內部改變依然影響函數外部
function test(a){
a.push(4);
alert(a)
}
test(a); //1,2,3,4
alert(a); // 1,2,3,4 全局變量已經被影響
以上代碼證明引用型哪怕用參數傳入也一樣會牽連。當然瞭如果重新賦值(不是用push修改)會切斷引用,徹底取消牽連:
var a=[1,2,3]; //引用型傳進之後在函數內部改變依然影響函數外部
function test(a){
a=[3,3,3,3,3,3]; //重新複製則不再受外界影響,因爲賦值切斷了引用
alert(a)
}
test(a); //3,3,3,3,3,3
alert(a); // 1,2,3 不再受影響
這些就是常見的面試題考查的知識點,把這些掌握能解決很多類型的面試題,希望對你有所幫助,一起努力。