一些js小題(一)

一些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




都知道函數中return後面的代碼永遠不會執行(不知道的面壁),但也不要太粗心,因爲對於函數聲明來說有個特性就是提前執行,也就是會把函數聲明的代碼放到代碼塊頂端優先執行,這樣哪怕該類函數是放在return後面依然會執行,並且在return前就執行:

                (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 不再受影響


這些就是常見的面試題考查的知識點,把這些掌握能解決很多類型的面試題,希望對你有所幫助,一起努力。














發佈了47 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章