基礎觀點
- 變量是存儲信息的容器,這裏須要辨別一下:變量不是指存儲的信息自身,而是指這個用於存儲信息的容器,能夠把變量設想成一個個用來裝東西的紙箱子
變量須要聲明,而且發起在聲明的同時舉行初始化,以下所示:
var aa = '1'; let bb = 2; const CC = 3;
假如從新聲明變量,該變量的值不會喪失
var aa = 'cc'; var aa; //此時的值照樣cc
變量名(標誌符)定名請求:
- 適用於變量/屬性/函數/函數參數的名字等
- 可由字母、数字、下劃線
_
及美圓符$
組成 - 不能夠運用關鍵字、保留字以及
true
、false
、null
、(eval
、arguments
嚴厲形式下) - 運用
undefined
雖然不會報錯,然則並不能聲明勝利,不管給它初始化為何,它的值依然為undefined
- 最好運用字母開首(還能夠運用
_
與$
)
值範例
- 變量能夠包括兩種差別數據範例的值:基礎範例值(簡樸的數據段)和援用範例值(能夠由多個值組成的對象)
- 因為一切援用範例的值都是
Object
的實例,所以能夠運用xx instanceof Object
來推斷是不是為援用範例的值,假如是則會返回true
,不然返回false
存儲體式格局
- 基礎範例值在內存中佔有牢固大小空間,因而被保留在棧內存中(棧由操縱系統自動分派開釋);
- 援用範例值是對象,保留在堆內存中;(堆:平常由順序員分派開釋, 若順序員不開釋,順序結束時能夠由
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
新增了let
和const
敕令用來聲明變量-
let
敕令,它的用法類似於var
,然則所聲明的變量,只在let
敕令地點的塊級作用域內有效,且在該塊級作用域內不可反覆聲明 -
const
聲明一個只讀的常量,一旦聲明,常量的值就不能轉變,與let
一樣,只在聲明地點的塊級作用域內有效,且在該塊級作用域內不可反覆聲明 -
const
實際上保證的,並非變量的值不得修改,而是變量指向的誰人內存地點不得修改。關於簡樸範例的數據(數值、字符串、布爾值),值就保留在變量指向的誰人內存地點,因而等同於常量。但關於援用範例的數據(主如果對象和數組),變量指向的內存地點,保留的只是一個援用地點(指針),const
只能保證這個援用地點(指針)是牢固的,至於它指向的堆內存中的存儲的值是不是是可變的,就完整不能掌握了。因而,將一個對象聲明為常量必需異常警惕。
-
- 未運用
var
/let
/const
舉行聲明,此時建立的變量為全局變量,只管不要如許做! -
var
敕令和function
敕令聲明的全局變量,是頂層對象的屬性,let
敕令、const
敕令、class
敕令聲明的全局變量,不屬於頂層對象的屬性(瀏覽器中為window
,node
中為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
塊內里的變量/函數)也會聲明提拔,能夠先運用后聲明,不影響外部同名變量/函數 -
let
和const
敕令轉變了語法行動,它們所聲明的變量肯定要在聲明后運用,不然報錯。因為let
和const
敕令在當前塊級作用域內不可反覆聲明所以當有同名函數時,會直接報錯Identifier xx has already been declared
參考資料
- 《JavaScript高等順序設計第三版》
- ECMAScript 6 入門
- MDN變量