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。