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