关于js中的命名
一、 重復聲明和遺漏聲明
使用 var 語句重復聲明變量是合法且無害的。如果重復聲明帶有初始化器,那就和賦值語句沒什么兩樣。讀取一個沒有聲明的變量的值時,JavaScript 會報錯。
二、關于局部變量
聲明局部變量時必須使用 var 語句,如果缺少 var 語句,則會給全局對象創建一個同名屬性。ES5 嚴格模式中,給一個沒有聲明的變量賦值會報錯。
三、函數作用域和申明提前
在一些類C編程語言中,花括號內的代碼有各自的作用域,而且在變量在聲明它們的代碼段外是不可見的,這稱為塊級作用域(block scope)。JavaScript 中沒有塊級作用域,而是使用函數作用域(function scope),即變量在申明它的函數及這個函數嵌套的任意函數內都是可訪問的。
for(var k=0; k<10; k++){console.log(k);}console.log(k);// 10,for 語句創建的變量for循環結束后,依然會存在于循環外部的環境中JavaScript 函數里聲明的所有變量(不涉及賦值)都被提前至函數頂部,即聲明提前(hoisting)。(聲明提前在 JavaScript 引擎“預編譯”時進行,細節參考 JavaScript Engine)
var scope = "global";function f() {console.log(scope); //輸出global?不,undefined。 why?var scope = "local"; //在這里聲明變賦值,但變量在函數體內任何地方是有定義的console.log(scope); // => local}//上面的函數執行時順序如下:function f() {var scope; //變量聲明提前至函數體頂部console.log(scope); //變量沒有初始化,所以undefinedscope = "local"; //變量初始化(賦值)保留在原來的位置console.log(scope);}?在有塊級作用域的編程語言中,讓變量聲明和使用變量的代碼盡量靠近,可以提高程序性能。JavaScript 沒有塊級作用域,因此可以把所有變量都放在函數體頂部,直觀反映變量作用域。
四、作為對象屬性的變量
聲明 JavaScript 全局變量時,實際上就是定義全局對象的一個屬性(對于瀏覽器而言,全局對象就是window),ES 中規定全局變量是全局對象的屬性。
- 使用 var 聲明全局變量時,創建一個不可配置的屬性,無法用 delete 運算符刪除
- 非嚴格模式下給未聲明變量賦值創建的全局變量,是全局對象的可配置屬性,可以刪除
- 可以使用 this 關鍵字引用全局對象
- var var1 = 1; // 不可配置全局屬性var2 = 2; // 可配置全局屬性console.log(this.var1); // 1console.log(window.var1); // 1delete var1; // false 無法刪除console.log(var1); //1delete var2;console.log(delete var2); // trueconsole.log(var2); // 已經刪除 報錯變量未定義
部變量可以當做跟調用函數相關的某個對象的屬性,ES3 稱該對象為調用對象(call object),ES5 稱為 聲明上下文對象(declarative environment record),JavaScript 目前沒有方法可以引用局部變量中存放的對象。
五、變量值的數據類型
ES 變量值分為兩種類型:
- 基本類型,指的是簡單的數據段。5種基本數據類型:Undefined、Null、Boolean、Number、String,這5中基本類型都是按值訪問的,因為可以操作保存在變量中的實際值。
- 引用類型,指可能有多個值構成的對象。引用類型的值時保存在內存中的對象,JavaScript 不能直接操作對象的內存空間,操作對象時,實際上是操作對象的引用而不是實際的對象。引用類型的值是按引用訪問的。
5.1、引用類型值的動態屬性
定義基本類型和引用類型的方式類似:創建一個變量并賦值。區別在于引用類型的值,可以添加屬性和方法,也可以改變和刪除屬性。基本類型的值不能添加屬性。
var person = new Object(); // 引用類型person.name = "Minhui"; // 添加屬性console.log(person.name); // => "Minhui"var name = "Minhui";name.age = 28; // 為基本類型添加屬性不會導致錯誤,但沒用console.log(name.age);// => undefined?5.2、變量值復制
從一個變量向另一個變量復制基本類型的值,會在變量對象上創建一個新值,然后把該值復制到位新變量分配的位置上。復制完成后,改變其中一個變量不會影響到另一個。
從一個變量向另一個變量復制引用類型的值時,同樣會將存儲在變量的值復制一份放到為新變量分配的空間中。區別是,這個值的副本實際上是一個指針,指針指堆內存中的一個對象。復制完成后,兩個變量引用同一個對象。改變其中一個變量,就會影響到另一個變量。
var obj1 = new Object();var obj2 = obj1;obj1.name = "Minhui";console.log(obj2.name); // => "Minhui"obj2.name = "Luo"; //修改obj2的屬性值會影響obj1obj2.firstName = "LUO"; // 添加屬性console.log(obj1.name); //=> Luoconsole.log(obj1.firstName); //=> LUO?向參數傳遞引用類型的值時,會把這個值在內存中的地址復制給一個局部變量,這個局部變量的的變化會反映在函數外部。
unction setName(obj) { obj.name = "Minhui"; //函數內部,obj和penson引用同一個對象 } var person = new Object(); setName(person); console.log(person.name); // => "Minhui",函數內部的變化函數外部也會有反映,因為堆內存中只有一個對象?上面的例子很容易讓開發者誤以為參數是按引用傳遞的,下面經過修改的例子證明對象是按值傳遞的:
function setName(obj) {obj.name = "Minhui";obj = new Object(); //函數內部重寫obj時,這個變量的引用就是一個局部對象,函數執行完畢后就被銷毀obj.name = "Django";}var person = new Object();setName(person);console.log(person.name); // => "Minhui",如果按引用傳遞,name屬性應該被改為 Django?
5.3變量類型檢測
- 基本數據類型檢測:使用 typeof,注意對象和 null 都返回 object。
- 引用類型:instanceof,語法為 variable instanceof constructor;使用instanceof 檢測基本類型值時始終返回 false。
?注意:typeof 檢測函數返回 function;Safari 5 之前版本和 Chrome 7 之前版本使用 typeof 檢測正則表達式返回 function(規范原因);IE 和 Firefox 對正則表達式應用 typeof 返回 object。
六、一個面試題
var v = 1;function f1() {console.log(v);}function f2() {v = 2;console.log(v);}function f3(v) {var a = function() {console.log(v);}return a;}function f4() {//alert(v);v = 4;var v = 5;console.log(v);}var f = f3(v);f1(); // 1 沒問題f(); // 1 沒問題f2(); // 2 很容易理解,全局變量v被修改為2f1(); // 2 沒問題f(); // 2? -> 錯,1f4(); // 5 沒問題:函數體內,局部變量優先級大于同名全局變量f1(); // 4? -> 錯:聲明提前,2f(); //4? -> 錯,1?
注釋中有問號的三個地方是最容易出錯的。
先來看倒數第二個,如果沒有理解聲明提前,就會認為 f4() 執行的時候將全局變量v的值覆蓋了。實際不是,將上面 f4 函數體內的 alert 前面的注釋刪了試試,彈出來的是 2 嗎? 不是!f4 執行時其實被“預編譯”成下面的樣子:
function f4() {var v; // 聲明提前至最前面,甚至在alert之前alert(v); // undefinedv = 4; // 局部變量,全局變量中的 v 沒有被修改v = 5;console.log(v);}?關于 f 的值始終是 1,我剛開始看的時候也有點迷惑。事實上,f3(v) 中的 v 和全局變量 v 并不是同一個東西,給變量 f 賦值時,其實相當于 var f = f3(1) ,傳入的是全局變量 v 的值,而不是 v 本身(按值傳遞?)。賦完值的函數 f 其實等同于:
f = function() {console.log(1); // v 再怎么變跟我有一毛錢關系}?
參考:http://csspod.com/archives/javascript-variable
?
附錄:對于單個字母的命名變量:
經常見單個字母的命名,如HAO123和豆瓣網時,常懷疑這樣有什么好處,其實這是他們發布的壓縮的版本:
jS優化工具,分兩類,一種是壓縮(去無用字符等等),一種是打包(變量替換)。
T?=?function(j,?h,?k)?{
????????var?m?=?"-", ????????i; ????????if?(!S(j)?&&?!S(h)?&&?!S(k))?{ ????????????i?=?j[z](h); ????????????if?(i?>?-1)?{ ????????????????k?=?j[z](k,?i); ????????????????if?(k?<?0)?k?=?j[D]; ????????????????m?=?j[H](i?+?h[z](N)?+?1,?k) ????????????} ????????} ????????return?m ????},對于寫來說,標識符當然是短的好,方便輸入,方便記憶
對于讀則是,標識符長的好,長的標識符包含的信息量相對的也多,結合上下文,可以很方便的理解語句塊的意思作用
但如果太短的話,寫的時候就因為信息量太少,導致記混了,反而變成不方便
太長也是,可能看一眼就明白,也可看過就忘了,另外屏幕空間有限,如果都是長長的……
====
對于編譯型語言,標識符長短不影響運行效率、執行文件大小,編譯的時候編譯器會將標識符替換為內存地址
對于解釋型語言,理論上對運行效率應該是有影響的,但……
?
總結
- 上一篇: 新装ubuntu10.04后的一些设置
- 下一篇: TOUCH(1)