Javascript高級程序設計——11.變量、作用域、緩存

1、變量及作用域

(1)ECMAScript的兩種數據類型:基本類型、引用類型值

a、基本類型:棧內存中簡單的數據段(完全保存在內存中的一個位置)

b、引用類型:堆內存中的對象(保存實際上只是一個指針,該指針指向內存中的另一個位置,該位置保存對象)

當把一個值賦值給變量時,解析器必須確定是基本類型,還是引用類型

a、基本類型(5種):undefined、null、boolean、string、number

特點:有固定大小的空間,值保存在棧空間

注意:某些語言中,字符串string以對象的形式來表示,被認爲引用類型,ECMAScript放棄該傳統

b、引用類型:Object{}類型

特點:內存大小不固定,值保存在堆內存空間中

操作:當查詢引用類型的變量時,先從棧中讀取內存地址,再通過地址找到堆中的值,即按引用訪問。


不同點:基本類型按值訪問,引用類型按引用訪問


(2)動態屬性

a、定義類型值方式爲:創建一個變量爲該變量賦值,

var box=new Object();  //{}
box.name=‘zhao’;    //新建一個屬性
alert(box.name);


b、基本類型

var box='zhao' ;  //基本類型值,是字符串;
box.age=28;
alert(box.age);  //undefined;


由於上述代碼不引用類型,所以無法輸出


(3)複製變量的值

基本類型:值本身

引用類型:複製爲地址

a、基本類型

var box='Lee';    //保存在box'Lee'
var box2=box;  //棧內潤再生成一個‘box2 'Lee'’
box2='kk';   //基本類型保持獨立,box不會進行復制
alert(box);     //Lee
alert(box2);   //kk


b、引用類型

var box=new Object();    //創建一個引用類型;
box.name='Lee';
var box2=box;
alert(box.name);      //‘Lee’
alert(box2.name);  //Lee

上述代碼中,由於是按照地址傳遞,所以box與box2是相同的,即當box.name變化時,box2.name也會變化。



(4)傳遞參數

a、基本類型(按值傳遞)

function box(num){
num+=10;
return num;
}
var num=50;
alert(box(num));    //60
alert(num);           //50
//(若按引用傳遞,那麼函數量的num會成爲類似於全局變量,也就是說,最後會打印60)


注意:Javascript中不會按照引用傳遞,所以不可能打印出60,但在php文件中可以按引用傳遞,即爲全局變量

demo1.php(按引用傳遞)

<?php
function box(&num) { //表示num爲全局變量
num+=10;
return num;
} 
var num=50;
echo box(num);   //60
echo '<br />';
echo num;     //60
?>


b、引用傳遞(傳參引用參數)

function box(obj){       //按值傳遞參數,傳遞一個引用類型的參數,而不是按值傳參,
obj.name='Lee';
var obj=new Object();     //所以,js沒有按引用傳遞參數功能,不能把傳遞引用參數當成引用傳參
obj.name='kkk';
}
var obj=new Object();
box(obj);
alert(obj.name);

結果:Lee

解析:若按引用傳參,即結果爲“kkk”,但是新建的object對象,表現的不能被外界看到。


易混點——按引用傳遞和傳遞引用類型

這兩個是不同的概念:

(1)按引用傳遞:函數中變量爲全局變量,在外部也可以訪問

(比如php中,必須在參數前加&號表示按引用傳遞)

(2)傳遞引用類型:函數中變量爲局部變量,在外部不可以訪問


總結:ECMAScript中沒有按引用傳遞,只能是局部變量,在PHP中可以實現。


(5)檢測類型

A——基本類型

必須採用typeof運算符進行檢測,但對於引用類型typeof就不可以,若不是檢測是否爲對象,而是檢測是何種類型的對象,採用instanceof運算符

function box(obj){       //按值傳遞參數,傳遞一個引用類型的參數,而不是按值傳參,
obj.name='Lee';
var obj=new Object();     //所以,js沒有按引用傳遞參數功能,不能把傳遞引用參數當成引用傳參
obj.name='kkk';
}
var obj=new Object();
box(obj);
alert(obj.name);

總結:數組array,空對象null,正則表達式regexp都表示的是“對象”;


B——引用類型

案例5-1:用instanceof運算符檢測引用類型

var box1=[1,2,3];
alert(instanceof Array);    //是否爲數組,返回true;
var box2={};
alert(instanceof Object) ;  //是否爲對象,返回true;
var box3=/g/;
alert(instanceof RegExp);  //是否爲正則表達式,返回false;


區別:typeof運算符、instanceof運算符

(1)typeof——檢測基本類型,一般返回基本類型(如object、number、string、null、boolean、undefined)

(2)instanceof——檢測引用類型,檢測某一個變量是否爲某一個數據類型,通常返回的是true或false

(注意:當用instanceof檢測基本類型時,會返回false,見案例4-2)

案例5-2:

var box=String();
alert(box instanceof String);   //檢測box是否爲對象,返回false(由於string爲基本類型)


若想返回true,即需要用基本類型方式來創建對象,見案例4-3

案例5-3:

var box=new Object('Lee');
alert(box instanceof String);   //返回true(由於有new關鍵字)


注意——

對基本類型而言,(1)若有new關鍵字創建對象並檢測時,用instanceof運算符

        (2)若無new關鍵字直接創建對象時,用typeof運算符


(6)執行環境及作用域

a、對於全局變量,位於最外圍,屬於window屬性

b、對於全局函數,位於最外圍,屬於window的方法

案例6-1:

var box='blue';
function setBox(){
	alert(window.box);        //全局變量即window的屬性
}
window.setBox();               //全局函數即window的方法;


注意:當執行完所有代碼後,該環境被銷燬,保存在其中的變量也將隨之被銷燬。


c、作用域“全局作用域window”、“局部作用域”

c-1:若局部子函數中有var,即爲局部變量;若無var,即可以取代之前的全局變量

	var box='Lee';
	function setBox(){
		//var box='red';  
		 //局部變量,範圍在setBox中,出去就被銷燬,結果爲“Lee”
		box='red';
		//box爲全局變量,結果爲“red”
	}
	setBox();
	alert(box);


(2)當傳參數時,也爲局部變量

	var box='Lee';
	function setBox(box){    //通過傳參,也是局部變量,作用與在setBox中;
		alert(box);
	}
	setBox('red');
	alert(box);

結果:仍爲“Lee”,由於該參數box在setBox()函數中,“red”參數進去執行完畢即被銷燬,並沒有傳遞到window下。


(3)當函數中包含着函數,即被包含的函數也是局部變量

var box='Lee';
function setBox(){
	function setColor(){         //setColor()執行作用域在setBox()中;
		//var b='kkk';           //變量b作用域位於setColor()中
		//alert(b);
		return 123;
	}
}
alert(window.setBox());    //123


(6)沒有塊級作用域

塊級作用域,即諸如if語句等花括號封閉的代碼塊,

所以,支持條件判斷萊斯你故意變量。

案例1:if、for語句沒有封閉作用域的功能,即可被外圍訪問,window下的全局變量。

if(true){
	var box='Lee';
}
alert(window.box);


案例6-2:var關鍵字在函數中使用

function box(){
	//var num=10;     //有var,在函數體內聲明變量,表示局部變量。
	num=10;            //無var,在函數體內表示全局變量
}
box();
alert(num);


(7)變量查詢

向上查詢搜索的功能

var box='blue';
function getColor(){
	var box='red';
	return box;
}
alert(getColor());

結果:返回red,由於在getColor()函數中已經存在box對象,就不必向外部window進行上一級搜索。


2、內存問題

(1)Javascript有自動垃圾收集功能,也就是說,執行環境會負責管理代碼執行過程中使用的內存。

(2)Javascript最常用的垃圾收集方式:標記清除。

(垃圾收集器會在運行的時候給存儲在內部變量加上標記,會去掉環境中正在使用變量的標記,而沒有被去掉的標記視爲準備刪除的變量,最後當垃圾收集器完成內存清理工作,銷燬那些帶標記的值並回收他們所佔用的內存空間)。

(3)優化內存的性能方法:一旦數據不再使用,將其設置爲null來釋放引用,即“解除引用”,

適用於大多數全局變量和全局對象

案例2-1:null解除引用的案例

var box={};
box.name='Lee';
alert(box.name);   //Lee


box=null;    //銷燬引用,等待清理;
alert(box);      //null


但是,若爲window的時候,不可以解除引用

案例2-2:

var box='Lee';
alert(window.box);  //Lee
window=null;
alert(window);     //Lee

解析:由於window不可能被設置爲null。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章