如何理解JavaScript中給變量賦值,是引用還是復制


一、JavaScript中值的類型

JavaScript中的值分為2大類:基本類型和引用類型。每種類型下面又分為5種類型。

基本類型:

     數字類型:Number;字符串類型:String;布爾類型:Boolean(true和false);Undefined;Null。

引用類型:

     函數、數組、日期、正則、錯誤。

注意:所有的引用類型都是對象,也就是Object對象下的一個類。

二、值和引用

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

    對基本類型,是按值訪問的,即通過值復制的方式來賦值和傳遞。

    對引用類型,是按引用訪問的,即通過引用復制的方式賦值和傳遞。在操作對象時,實際上是在操作對象的引用,而不是實際的對象。

下面通過示例來理解兩者的區別。

例1:

    以數字基本類型值為例,將數字賦給變量a,此時a持有的是該值的一個復制本。再將a賦給變量b,此時b持有的是該值得另一個復制本,不論b怎么變化,都不會影響a的值。

    注意:所有的基本類型值都是不會變的。比如一個字符串"abcd",它的值永遠是"abcd",不可能發生改變。如果把它賦給一個變量,var x="abcd",然后給x賦其他的值,那么x的值可以改變,但是abcd"這個字符串本身的值沒有發生任何變化。包括使用某些自帶的函數,比如x.toUpperCase();這個函數返回的是x字符串的大寫形式"ABCD"。注意,是“返回”一個值,而不是改變原有的值。此時,變量x的值仍然是"adcd",除非你使用了x=x.toUpperCase()。(即重新對變量賦值了)

    對於基本類型,將其值賦給一個變量時,就是將這個值賦值給了變量,值本身不會發生任何變化。在給變量重新賦值后,變量的值就變化了。變量之間是可以比較的,比較的就是他們本身的值。

例2:

    以數組引用類型為例。JavaScript支持在定義變量的時候同時給它賦值,即var a=[1,2,3]同時定義一個對象並將其賦值給變量。

    定義一個對象(數組[1,2,3]),此時這個對象在內存中建立。當給把這個對象賦值給一個變量時,變量a僅僅是對這個對象的引用,而不是將該對象復制到了該變量中。即變量a中存儲的是指向對象的地址。將a的值賦給b,也即將a中的地址賦給了變量b。這是變量a和b都指向同一個對象。所以b值得改變就會直接引起對象本身的改變,因為變量a也指向這個數組,所以a的值肯定也會發生變化。

    注意:對象的比較與基本類型值不同。即使兩個對象完全相同,比如兩個完全相同的數組,它們也是不相等的。只有兩個變量指向同一個對象時,它們才是相等的。如:

var a = [1,2,3],b = [1,2,3];
console.log(a===b);//false
var c=a;
console.log(c===a);//ture

 

例3:

    例3與例2的區別在於,對b進行了重新賦值操作,b就不再是引用a的指向,並與a的指向沒有任何關系,而是指向了一個新的數組[1,2,3,4],所以b的操作也不再影響到a指向的值。

例4:函數-無重新賦值

    將數組賦值給變量a后,a指向數組[1,2,3]。調用函數foo(a)之后,向數組中插入數字4,原數組發生變化,所以a也跟着變成[1,2,3,4]。

例5:函數-有重新賦值

  • 定義數組[1,2,3]並賦值給變量a,a指向該數組。
  • 調用函數foo(a),執行的操作是:

        1、向原數組中插入數字4,原數組變成[1,2,3,4];

        2、定義新數組[4,5,6],並重新賦值給a。此時變量指向了新數組,原數組保持[1,2,3,4]不變;

        3、向變量中插入數字7,由於此時變量指向了新數組,所以此步操作改變了新數組[4,5,6],新數組又變成另一個新數組[4,5,6,7];

        4、執行console.log操作,顯示的是這個最新的數組,即[4,5,6,7]。

  • 函數外執行console.log操作。由於函數中,只有第一步操作改變了原數組,后續操作改變的是新賦值的數組[4,5,6](新賦值之后,變量a指向了該新數組,所有后續操作,都是針對的新數組),所有該步操作的結果顯示的是[1,2,3,4]。

例6:函數-清空當前引用的數組

  • 定義數組[1,2,3]並賦值給變量a,a指向該數組。
  • 調用函數foo(a),執行的操作是:

        1、向原數組中插入數字4,原數組變成[1,2,3,4];

        2、清空數組。由於此時變量仍然指向原數組,所以此處操作針對的是原數組,即清空原數組;

        3、向數組中插入數字4,5,6,7。由於沒有重新賦值操作,變量仍然指向原數組,所以原數組變為新數組[4,5,6,7];

        4、執行console.log操作,顯示的是這個最新的數組,即[4,5,6,7]。

  • 函數外執行console.log操作,由於函數中變量都沒有重新賦值,所以每一步操作針對的都是原數組,最終原數組變成了這個最新的數組,即[4,5,6,7]。

三、更多例子

例1:

    當多個變量持有同一對象的引用時,通過其中的任何一個,都可以改變對象。

例2:

     對比代碼可知,test1和test2的區別在於,變量a在test1中不斷地賦值新的引用,導致a與b持有的引用不同,后面向a添加的屬性,b都無法訪問到。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM