国产精品成人VA在线观看,亚洲日韩在线中文字幕综合,亚洲AV电影天堂男人的天堂,久久人人爽人人爽人人av东京热

News新聞

業(yè)界新聞動態(tài)、技術前沿
Who are we?

您的位置:首頁      JS/JQ/AJAX      javascript 變量和作用域

javascript 變量和作用域

標簽: 發(fā)布日期:2014-04-25 00:00:00 397

今天學習了javascript 的變量和作用域的基本知識,對于以前在開發(fā)中遇到的一些不懂的小問題也有了系統(tǒng)的認識,收獲還是比較多的。

 
【基本類型和引用類型】
 
ECMAScript 變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值。基本類型值指的是簡單的數(shù)據(jù)段,而引用類型值指那些可能由多個值構成的對象。我們常見的五種基本類型的值:Undefined、Null、Boolean、Number 和 String ,這五種基本數(shù)據(jù)類型是按值訪問的,因此可以操作保存在變量中的實際的值。引用類型的值是保存在內存中的對象,也就是說不能夠直接操作對象的內存空間,引用類型的值是按引用訪問的。注意:我們不能給基本類型的值添加屬性,例如以下代碼:
 
var name = 'name1';
name.age = 22;
console.log(name.age);     // undefined 
【復制變量值】
 
從一個變量向另一個變量復制基本類型值很引用類型值時存在不同的情況,如果從一個變量向另一個變量復制基本類型的值,會在變量對象上創(chuàng)建一個新值,然后把該值復制到為新變量分配的位置上,例如:
 
var num1 = 5;
var num2 = num1;
通過以上的復制方式,num1 中的 5 和 num2 中的 5 是完全獨立的,也就是說修改 num1 或者 num2 是不會影響到另外一個值的,我們參考如下的代碼:
 
var num1 = 5;
var num2 = num1;
console.log(num1,num2);  // 5  5
num1 = 6;
console.log(num1,num2);  // 6  5
下面的表格形象的展示的復制基本類型值的一個過程:
 
 
 
復制前的變量對象 復制后的變量對象
     
    num2
5
 
(Number類型)
 
num1
5
 
(Number類型)
 
num1
 
5
 
(Number類型)
 
 
 
當從一個變量向另一個變量復制引用類型的值的時候,同樣也會將存儲在變量對象中的值復制一份放到為新變量分配的空間中。但是這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復制操作結束后,兩個變量引用的其實是一個值。因此,改變任意一個變量都會影響到另外一個變量。例如以下代碼:
 
復制代碼
var per1 = new Object();
var per2 = per1;
per1.name = 'name1';
console.log(per1.name,per2.name);   //  name1 name1 
per1.name = 'name2';
console.log(per1.name,per2.name);  // name2 name2 
per2.name = 'name3';
console.log(per1.name,per2.name);   //  name3 name3
復制代碼
下圖詳細的展示了保存在變量對象中和保存在堆中的對象之間的關系:
 
 
 
【傳遞參數(shù)】
 
ECMAScript 中所有函數(shù)的參數(shù)都是按值傳遞的,也就是說,把函數(shù)外部的值復制給函數(shù)內部的參數(shù),就和把值從一個變量復制到另外一個變量一樣?;绢愋椭档膫鬟f如同基本類型變量的復制一樣,引用類型的傳遞如同引用類型變量的復制一樣。例如以下代碼:
 
復制代碼
function addNum(num){
    num += 10;
    return num;
}
var count = 20;
var result = addNum(count);
console.log(count,result);   // 20 30
復制代碼
這里的函數(shù) addNum() 有一個參數(shù) num ,而參數(shù)實際上是函數(shù)的局部變量。在調用這個函數(shù)時,變量 count 作為參數(shù)被傳遞給函數(shù),這個變量的值是20。于是,數(shù)值20被復制給參數(shù) num 。但是 num 的改變并不能影響 count 的值,所以 count 輸出的值仍然是20 。再舉一個例子:
 
function setName(obj){
    obj.name = 'name5';
}
var newObj = new Object();
setName(newObj);
console.log(newObj.name);  // name5
這段代碼看起來是在局部作用域中修改了 newObj 的 name 的值,在全局作用域也反映出來了,這樣的理解是錯誤的。再看一段代碼:
 
復制代碼
function setName(obj){
    obj.name = 'name6';
    var obj = new Object();
    obj.name = 'name7';
}
var newObj = new Object();
setName(newObj);
console.log(newObj.name);  //  name6
復制代碼
對比兩段代碼可以看出,如果 newObj 是按引用傳遞的,那么 newObj 的 name 屬性應該是 name7 才對,但是 name 屬性是 name6,這說明及時在函數(shù)內部修改了參數(shù)的值,但原始的引用仍然保持未變。
 
【執(zhí)行環(huán)境和作用域】
 
執(zhí)行環(huán)境定義了變量或函數(shù)有權訪問的其他數(shù)據(jù),決定了他們各自的行為。全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境,在Web瀏覽器中,全局執(zhí)行環(huán)境被認為是 window 對象,因此所有的全局變量和函數(shù)都是作為 window 對象的屬性和方法創(chuàng)建的。每個函數(shù)都有自己的執(zhí)行環(huán)境。當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,時鐘都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境是函數(shù),則將其活動對象作為變量對象。作用域鏈中的下一個變量對象來自包含(外部)環(huán)境,再下一個變量對象則來自下一個包含環(huán)境。全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈的最后一個對象。標識符解析是沿著作用域鏈一級一級的搜索標識符的過程。請看如下代碼:
 
復制代碼
var color = 'blue';
function changeColor(){
    if(color == 'blue'){
        color = 'red';
    }
    else{
        color = 'blue';
    }
}
changeColor();
console.log(color);     // red
復制代碼
函數(shù) changeColor() 的作用域包含兩個對象:它自己的變量對象(其中定義著 arguments 對象)和全局環(huán)境的變量對象。當 changeColor 在執(zhí)行的時候,在自己的作用域中并沒有找到 color ,于是便到全局環(huán)境中找,找到了 color 的值為 blue ,然后按照 changeColor() 函數(shù)的規(guī)則將 color 的值設置為 red 。再看一段更加詳細的代碼:
 
復制代碼
//這里只能訪問 color
var color = 'blue';
function changeColor(){   //這里可以訪問 color 、newColor ,但是不能訪問 temColor 
    var newColor = 'red';
    function swapColor(){  //這里可以訪問 color 、newColor 和 temColor
        var temColor = newColor;
        newColor = color;
        color = temColor;
    }    
    swapColor();
    console.log(color,newColor);   //red blue 
}
function showColor(){
    console.log(color);    //blue
}
showColor();
changeColor();
復制代碼
代碼的內容自己體會一下,這里不做詳細的解釋。
 
【沒有塊級作用域】
 
看如下的代碼:
 
for(var i = 0;i < 10;i ++){
    i += 1;
}
console.log(i);   // 10
對于有塊級作用域的語言來說, for 語句初始化變量的表達式所定義的變量,只會存在于循環(huán)的環(huán)境之中。在 javascript 中, i 并會在 for 循環(huán)執(zhí)行結束后被銷毀,反而被添加到了當前的執(zhí)行環(huán)境(全局環(huán)境)中。
 
1.聲明變量
 
使用 var 聲明的變量會自動被添加到最接近的環(huán)境中。在函數(shù)內部,最接近的環(huán)境就是函數(shù)的局部環(huán)境。請看如下代碼:
 
復制代碼
function addNum(num1,num2){
    var num = num1 + num2;
    return num;
}
var result = addNum(10,20);
console.log(result);    // 30
console.log(num);      // num is not defined 
復制代碼
以上代碼如果不使用 var 聲明 num 的話是不會導致錯誤的,例如:
 
復制代碼
function addNum(num1,num2){
    num = num1 + num2;
    return num;
}
var result = addNum(10,20);
console.log(result);    // 30
console.log(num);      // 30
復制代碼
2.查詢標識符
 
當在某個環(huán)境中為了讀取或寫入而引用一個標識符時,必須通過搜索來確定該標識符實際代表什么。搜索過程從作用域鏈的前端開始,向上逐級查詢與給定名字匹配的標識符。如果在局部環(huán)境中找到該標識符,搜索過程停止,變量就緒。如果在局部變量中沒有找到該變量名,則繼續(xù)沿作用域鏈向上搜索。搜索過程會一致追溯到全局環(huán)境變量。如果在全局環(huán)境變量也沒有找到該標識符,說明該變量尚未定義。請查看以下代碼:
 
var color = 'blue';
function getColor(){
    return color;
}
console.log(getColor());   // blue
getaColor() 在搜索局部變量的時候沒有找到 color ,而函數(shù)執(zhí)行語句是一定要返回一個 color ,與是便到全局環(huán)境變量中去搜索,找到了 color 。需要注意的是,搜索的過程中如果存在一個局部變量的定義,則搜索會自動停止,不再進入另一個變量對象。也就是說,如果局部環(huán)境存在著同名標識符,就不會使用位于父環(huán)境的標識符,例如以下代碼:
 
var color = 'blue';
function getColor(){
    var color = 'red';
    return color;
}
console.log(getColor());   // red
作用域鏈對于理解閉包的概念至關重要,還忘能夠加深理解。