JavaScript基礎系列---變量及其值類型

基礎概念

  • 變量是存儲信息的容器,這裏須要區分一下:變量不是指存儲的信息自己,而是指這個用於存儲信息的容器,能夠把變量想象成一個個用來裝東西的紙箱子
  • 變量須要聲明,而且建議在聲明的同時進行初始化,以下所示:node

    var aa = '1';
    let bb = 2;
    const CC = 3;
  • 若是從新聲明變量,該變量的值不會丟失程序員

    var aa = 'cc';
    var aa; //此時的值仍是cc
  • 變量名(標誌符)命名要求:es6

    • 適用於變量/屬性/函數/函數參數的名字等
    • 可由字母、數字、下劃線_及美圓符$組成
    • 不可使用關鍵字、保留字以及truefalsenull、(evalarguments嚴格模式下)
    • 使用undefined雖然不會報錯,可是並不能聲明成功,不管給它初始化爲何,它的值仍然爲undefined
    • 最好使用字母開頭(還可使用_$

值類型

  • 變量可能包含兩種不一樣數據類型的值:基本類型值(簡單的數據段)和引用類型值(可能由多個值構成的對象)
  • 由於全部引用類型的值都是Object的實例,因此可使用 xx instanceof Object 來判斷是否爲引用類型的值,若是是則會返回true,不然返回false
  • 存儲方式segmentfault

    • 基本類型值在內存中佔據固定大小空間,所以被保存在棧內存中(棧由操做系統自動分配釋放);
    • 引用類型值是對象,保存在堆內存中;(堆:通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收)
  • 訪問方式數組

    • 對於基本類型,變量存儲的是具體的值,能夠按值訪問,直接操做存儲的值
    • 對於引用類型,變量存儲的是對象引用地址(指針),是按引用訪問,當查詢時,咱們須要先從棧中讀取存儲的內存地址,而後再順藤摸瓜地找到保存在堆內存中的值
  • 複製變量值瀏覽器

    • 複製時,基本類型拷貝的是具體的值,而引用類型拷貝的是引用地址,因此引用類型賦值時要格外注意!!!
    //基本類型賦值
    var num1 = 10;
    var num2 = num1;
    console.log(num1,num2);// 10, 10
    num2 = 100;
    console.log(num1,num2);// 10, 100
    
    //引用類型賦值
    //person2拷貝了person1的引用地址,因此person1和person2實際上指向的是同一個對象
    //因此改變person2會影響到person1
    var person1 = {
        name:'cc'
    };
    var person2 = person1;
    console.log(person1.name, person2.name);// cc, cc
    person2.name = 'cshine';
    console.log(person1.name, person2.name);// cshine, cshine
    
    var arr1 = [1,2,3];
    var arr2 = arr1;
    console.log(arr1, arr2);// [1, 2, 3], [1, 2, 3]
    arr2[1]= 'string';
    console.log(arr1, arr2);// [1, "string", 3], [1, "string", 3]
  • 傳遞參數函數

    • ECMAScript中全部的函數的參數都是按值傳遞,即便是引用類型值的傳遞也是按值傳遞
    • 傳遞基本類型值時,被傳遞的值會被複制給一個局部變量(即命名參數或者arguments中的一個元素)
    • 傳遞引用類型值時,引用類型值是一個引用地址(指針),它也會複製給一個局部變量,這個局部變量再根據這個地址去按引用訪問對象,所以這個局部變量的變化會反映在函數的外部。因此仍是按值傳遞,而不是由於它是按引用傳遞才致使局部變量的變化會反映在函數的外部

注意點

  • es6新增了letconst命令用來聲明變量操作系統

    • let命令,它的用法相似於var,可是所聲明的變量,只在let命令所在的塊級做用域內有效,且在該塊級做用域內不可重複聲明
    • const聲明一個只讀的常量,一旦聲明,常量的值就不能改變,與let同樣,只在聲明所在的塊級做用域內有效,且在該塊級做用域內不可重複聲明
    • const實際上保證的,並非變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。但對於引用類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個引用地址(指針),const只能保證這個引用地址(指針)是固定的,至於它指向的堆內存中的存儲的值是否是可變的,就徹底不能控制了。所以,將一個對象聲明爲常量必須很是當心。
  • 未使用var/let/const進行聲明,此時建立的變量爲全局變量,儘可能不要這樣作!
  • var命令和function命令聲明的全局變量,是頂層對象的屬性,let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性(瀏覽器中爲windownode中爲global
  • 對於var/let來講,只聲明而未初始化,此時變量存儲的信息是「空」的,也就是undefined;可是對於const來講,只聲明而不進行初始化是不容許的,會拋出Missing initializer in const declaration的錯誤,由於const定義的是常量,一旦定義便不可更改。

聲明提高(hoisting

  • var命令聲明的變量會發生」聲明提高「現象,即變量能夠在聲明以前使用,值爲undefined設計

    console.log(aa);// undefined
    var aa = 'string';
    console.log(aa);// string
  • function聲明的函數也會發生」聲明提高「現象,函數在聲明以前可使用,值爲指向該函數的指針;可是若是是在支持ES6的環境中,ES6容許在塊級做用域內聲明函數,此時在塊級做用域中聲明的函數,會提高到所在的塊級做用域的頭部,值爲整個函數塊,同時還會提高到塊級做用域外,可是值爲undefined。(環境致使塊級做用域內聲明函數的行爲差別很是大,因此應該避免在塊級做用域內聲明函數。若是確實須要,也應該寫成函數表達式,而不是函數聲明語句)指針

    console.log(fn);// ƒ fn(){}
    function fn(){}
    console.log(fn);// ƒ fn(){}
    
    //支持es6的環境中
    console.log(fb);// undefined
    if(true){
        console.log(fb); // ƒ fb(){}
        function fb(){}
    }
    console.log(fb);// ƒ fb(){}
    
    console.log(fc);// undefined
    if(false){
        console.log(fc); // 未執行
        function fc(){}
    }
    console.log(fc);// undefined
    fc() //Uncaught TypeError: fc is not a function
  • 函數和變量都會聲明提高,此時若函數名和變量名同名,函數名的優先級要高;可是正式執行代碼時,同名函數會覆蓋只聲明卻未賦值的變量,可是它不能覆蓋聲明且賦值的變量(緣由分析可見另外一篇文章JavaScript基礎系列---執行環境與做用域鏈)

    console.log(bb);// ƒ bb(){}
    var bb;
    function bb(){}
    console.log(bb);// ƒ bb(){}
    
    
    console.log(cc);// ƒ cc(){}
    var cc = 'string';
    function cc(){}
    console.log(c)c;// string
  • 局部變量/函數(函數做用域function塊裏面的變量/函數)也會聲明提高,能夠先使用後聲明,不影響外部同名變量/函數
  • letconst命令改變了語法行爲,它們所聲明的變量必定要在聲明後使用,不然報錯。因爲letconst命令在當前塊級做用域內不可重複聲明因此當有同名函數時,會直接報錯Identifier xx has already been declared

參考資料

相關文章
相關標籤/搜索