前面的話
關於javascript,第一個比較重要的概念是變量,變量的工作機制是javascript的基本特性。實際上,變量是標識符的一種。本文將詳細介紹變量和標識符
定義
標識符(Identifier)就是一個名字,用來對變量、函數、屬性、參數進行命名,或者用做某些循環語句中的跳轉位置的標記
//變量 var Identifier = 123; //屬性 (new Object).Identifier = 'test'; //函數及參數 function IdentifierName(Identifier1){}; //跳轉標記 Identifier: for(var i = 0; i < 5; i++){ if(i == 3){ break Identifier; } }
在日常生活中,有些東西是固定不變的,有些東西則會發生變化。例如,人的姓名和生日是固定不變的,但心情和年齡卻會隨着時間變化而變化。人們把那些會發生變化的東西稱為變量
當程序需要將值保存起來以備將來使用時,便將其賦值給一個變量。變量(variable)是一個用於保存值的占位符,可以通過變量名稱來獲得對值的引用
命名規則
在詞法結構一文中,我們介紹到javascript是一門區分字母大小寫的語言,且和其他任何編程語言一樣,javascript保留了一些標識符為自己所用,保留字不能用做普通的標識符
[注意]保留字包括關鍵字、未來保留字、空字面量和布爾值字面量
保留字 ReservedWord ::
Keyword
FutureReservedWord
NullLiteral
BooleanLiteral
此外,javascript預定義了很多全局變量和函數,應該避免把它們的名字用做標識符名
arguments Array Boolean Date decodeURI decodeURIComponent encodeURI
encodeURIComponent Error eval EvalError Function Infinity isFinite
isNaN JSON Math NaN Number Object parseFloat parseInt RangeError
ReferenceError RegExp String SyntaxError TypeError undefined URIError
javascript標識符名允許包含字母、數字、美元符號和下划線(但第一個字符不允許是數字)
//錯誤示范 6num //開頭不能用數字 %sum //開頭不能用除(_ $)外特殊符號,如(% + /等) sum+num //開頭中間不能使用除(_ $)外特殊符號,如(% + /等)
javascript允許標識符中出現 Unicode字符全集中的字母和數字(包括中文)。因此,程序員也可以使用非英語語言或數學符號來書寫標識符
var 測試文字 = 'test';
[注意]出於可移植性和易於書寫的考慮,通常我們不使用擴展的ASCII或Unicode字符
通常駝峰格式是標識符命名的首選格式,第一個字母小寫,剩下的每個單詞的首字母大寫
var myMoodToday = 'happy';
對於不同的數據類型,javascript有約定俗成的標識符名命名規則
類型 前綴 示例
數組(Array) a aItems
布爾值(Boolean) b bIsComplete
浮點數(Float) f fPrice
函數(Function) fn fnHandler
整數(Integer) i iItemCount
對象(Object) o oDIv1
正則表達式(RegExp) re reEmailCheck
字符串(String) s sUserName
變量(Variant) v vAnything
上面這種命名方法,叫匈牙利命名法。現在當前主流的編程規范都不推薦這種命名法
一般來說,變量的命名要使用名詞,而函數應該是動詞+名稱的形式
var count = 10; var myName="xiaohuochai"; var found = true; function getName(){ return 123; }
對於變量命名來說,盡量要在變量名中體現出值的數據類型
比如,命名count、length和size表明數據類型是數字,而命名name、title和message表明數據類型是字符串。用單個字符命名的變量諸如i、j、k通常在循環中使用
而對於函數和方法命名來說,第一個單詞應該是動詞,下面是一些使用動詞常見的約定
can 函數返回一個布爾值 has 函數返回一個布爾值 is 函數返回一個布爾值 get 函數返回一個非布爾值 set 函數用來保存一個值
變量聲明
聲明
在javascript中,使用一個變量之前應當先聲明(declare),變量是使用關鍵字var(variable的縮寫)來聲明的
var i; var sum;
也可以通過一個var關鍵字來聲明多個變量
var i ,sum;
賦值
把值存入變量的操作稱為賦值(assignment)。一個變量被賦值以后,我們就說該變量包含這個值
給變量第一次賦值的過程,叫初始化
我們可以將變量的初始賦值和變量聲明合寫在一起
var message = 'hello'; var i=0,j=0,k=0;
如果未在var聲明語句中給變量指定初始值,那么雖然聲明了這個變量,但在給它存入一個值之前,它的初始值就是undefined
在for循環和for-in循環中同樣可以使用var語句,這樣可以更簡潔地聲明在循環語法內中使用的循環變量
for(var i=0; i<10; i++)console.log(i);
變量可以在聲明時賦值,但不能有其他操作,如+=、-=等
var a = 2;//是正確的 var a += 2;//是錯誤的 var a = 2++;//是錯誤的,++只能用於變量,不能用於常量
重復聲明
使用var語句重復聲明變量是合法且無害的,如果重復聲明且帶有賦值操作,相當於重新賦值

遺漏聲明
如果試圖讀取一個沒有聲明的變量的值,javascript會報錯
<script> 'use strict'; a = 5; console.log(a); </script>
變量特性
javascript變量是弱類型(也叫松散類型)的,所謂松散類型就是可以用來保存任何類型的數據
編程語言分為動態類型語言和靜態類型語言兩種。 動態類型語言是指在運行期間才去做數據類型檢查的語言,也就是說,在用動態類型的語言編程時,不用給任何變量指定數據類型,該語言會在第一次賦值給變量時,在內部將數據類型記錄下來。javascript就是動態類型語言的代表
在javascript中,可以在修改變量值的同時修改值的類型
var message = 'hi'; message = 100;//有效,但不推薦
變量松散類型的特性總結起來有兩點:一是聲明時不用給變量指定數據類型;二是賦值時可以修改數據類型
變量作用域
變量的作用域(scope)是程序源代碼中定義這個變量的區域
作用域分為全局作用域和函數作用域(又叫局部作用域)兩種
全局作用域是最外圍的一個執行環境,在web瀏覽器中,全局執行環境被認為是window對象。所有全局變量和函數都是作為window對象的屬性和方法創建的。全局變量擁有全局作用域,在javascript代碼中的任何地方都是有定義的。全局作用域直到應用程序退出例如關閉網頁或瀏覽器時才會被銷毀
在函數內聲明的變量只在函數體內有定義。它們是局部變量,作用域是局部性的。函數參數也是局部變量,它們只在函數體內有定義。函數作用域中的所有代碼執行完畢后,該作用域被銷毀,保存在其中的所有變量和函數定義也隨之銷毀
function test(){ var message = 'hi'; } test(); alert(message);//錯誤
如果省略var操作符,則會創建一個全局變量
function test(){ message = 'hi'; } test(); alert(message);//'hi'
雖然省略var操作符可以定義全局變量,但並不推薦。在局部作用域中定義的全局變量很難維護,而且如果有意地忽略了var操作符,也會由於相應變量不會馬上就有定義而導致不必要的混亂,給未經聲明的變量賦值在嚴格模式下會導致拋出ReferenceError錯誤
在函數體內,局部變量的優先級高於同名的全局變量,如果在函數內聲明的一個局部變量或者函數參數中帶有的變量和全局變量重名,那么全局變量就被局部變量遮蓋
var scope = 'global'; function checkscope(){ var scope = 'local'; return scope; }; checkscope();//'local'
聲明提升(hoisting)
塊級作用域
塊級作用域是指花括號內的每一段代碼都具有各自的作用域,而javascript沒有塊級作用域。javascript只有函數作用域:變量在聲明它們的函數體以及這個函數體嵌套的任意函數體內都是有定義的
這意味着,變量在聲明之前甚至已經可用。javascript這個特性被非正式地稱為聲明提升(hoisting),javascript函數里聲明的所有變量(不涉及賦值)都被提前到函數體的頂部
[注意]其實除了變量提升,函數也被提升,到函數部分會有詳細介紹
var scope = 'global'; function f(){ console.log(scope);//undefined var scope = 'local'; console.log(scope);//'local' }
//變量聲明提升之后,相當於下面代碼 var scope = 'global'; function f(){ var scope; console.log(scope);//undefined scope = 'local'; console.log(scope);//'local' }
javascript中沒有塊級作用域,所以一些程序員特意將變量聲明放在函數體頂部,這種源代碼非常清晰地反映了真實的變量作用域
屬性變量
當聲明一個javascript全局變量時,實際上是定義了全局對象window的一個屬性
當使用var聲明一個變量時,創建的這個變量是不可配置的,也就是說這個變量無法通過delete運算符刪除
var truevar = 1; console.log(truevar,window.truevar);//1 1 delete truevar;//false console.log(truevar,window.truevar);//1 1
如果沒有使用嚴格模式並給一個未聲明的變量賦值的話,javascript會自動創建一個全局變量,以這種方式創建的變量是全局對象的正常的可配置屬性,並可以刪除它們
[注意]IE8-瀏覽器下,如果刪除window屬性時,不論該屬性是如何創建的,都會報錯
window.fakevar1 = 10; this.fakevar2 = 20; var fakevar3 = 30; fakevar4 = 40; console.log(delete fakevar1);//IE8-瀏覽器報錯,其他瀏覽器返回true console.log(delete fakevar2);//IE8-瀏覽器報錯,其他瀏覽器返回true console.log(delete fakevar3);//所有瀏覽器都返回false console.log(delete fakevar4);//所有瀏覽器都返回true
javascript全局變量是全局對象的屬性,這是在ECMAScript中強制規定的。局部變量當做跟函數調用相關的某個對象的屬性。ECMAScript3稱為調用對象(call object),ECMAScript5稱為聲明上下文對象(declarative environment record)。javascript允許使用this關鍵字來引用全局對象,卻沒有辦法可以引用局部變量中存放的對象。這種存放局部變量對象的特有性質,是一種對我們不可見的內部實現
參考資料
【1】 ES5/語法 https://www.w3.org/html/ig/zh/wiki/ES5/lexical
【2】 阮一峰Javascript標准參考教程——語法概述 http://javascript.ruanyifeng.com/grammar/basic.html
【3】 W3School-Javascript高級教程——ECMAScript變量 http://www.w3school.com.cn/js/pro_js_variables.asp
【4】《javascript權威指南(第6版)》第3章 類型、值和變量
【5】《javascript高級程序設計(第3版)》第3章 基本概念 第4章 變量、作用域和內存問題
【6】《javascript語言精粹(修訂版)》第2章 語法
【7】《javascript DOM編程藝術(第2版)》第2章 Javascript語法
