這次來點直接的,算是對Javascript的總結吧,到現在為止Javascript的心得也寫了不少了,很多體會,也收集了很多博主的部落格,也許以後學習的時候,自己的部落格和這些收集的部落格就是自己常去的地方。
var str = "liuyu";var test = function () { alert(str); alert(this.str);
alert(window.str);
}test();
上面這個代碼很容易理解,這裡的str就是全域變數,因為在後面是直接調用函數,所以this指的就是window,所有的全域變數都認識是附加在window對象上的,而window對象我們不可能陌生,也就不多說了,這裡有這幾個知識點:
1、範圍,Javascript中的範圍是以函數劃分開來的,當在函數裡面訪問變數的時候,如果函數內部沒有該變數,那麼就在上一個範圍中找,直到找到位置。
2,動態性,Javacript中的對象可以動態增加屬性和方法,定義的變數都相當於是附加在window對象上的,window可以省略。
var str = "liuyu";var test = function () { var str = "test"; alert(str); alert(this.str);}test();
上面這段代碼告訴我們,函數內部定義的變數會覆蓋函數外部定義的全域變數,其實並不是這麼簡單,因為在test這個函數的範圍內,已經定義了str變數,既然可以找到那麼就不往它的上一級範圍尋找。
var test = function () { str = "test"; alert(str); }test();alert(window.str);
上面這段代碼告訴我們,函數內所有沒有var開始的變數都是全域變數,其實就是附加在window上的。
var test = function () { str = 1; alert(str); alert(window.str); var str = 10; alert(str); alert(window.str);}test();alert(window.str);
這段代碼啟動並執行結果,可能會讓大家大吃一驚,我在開始運行這段代碼的時候也有類似的感覺,其實細細想起來並不是這麼複雜,但是如果要深究的話,意味無窮。
這段代碼和Javascript的解釋和運行有關係的。
Javascript是指令碼語言,其過程分為解釋(先行編譯)和運行過程,先行編譯過程中用於確定變數和函數等,這個時候並不賦值,賦值是在運行階段的。因為是從上往下運行,所以大家能看到undefined這個語句。
因為在test中定義了var str這個局部變數,這個過程是在先行編譯階段中完成的,雖然這個變數定義在最後,賦值是在運行階段完成。這裡要說明一點,就是範圍內的變數不管在函數的哪裡聲明,javascript都會在函數運行前在範圍內包含該變數。
//下面的代碼在window對象中建立一個屬於自己的對象或者命名空間,並把自執行函數中的方法附加到這個對象上,以便於我們調用這個自執行函數中的一些功能。 (function() { //根據id擷取對象 function _$(id) { return document.getElementById(id); } //建立一個自己的對象相當於C#中的命名空間(javascript中沒有命名空間這個說法,剛才已經說了牽強附會)window.liuyu = {}; //將內建函式_setStyle封裝在mySpace命名空間內 window.liuyu.$ = _$; })(); //測試代碼 window.onload = function() { var divtest=window.liuyu.$("testdiv");} //如果不使用這種方法,那麼,下面的方法也可以實現的。 window.liuyu= {}; window.liuyu.$ = function(id) { return document.getElementById(id); } //測試代碼 window.onload = function() { var divtest=window.liuyu.$("testdiv"); }
這段代碼內容比較大,但是很多都在前面介紹過,這裡用到了閉包,閉包可以類比靜態變數類等,可以參閱:http://www.cnblogs.com/zhangle/archive/2010/07/02/1770206.html。這裡還用到了自執行函數,甚至是偽裝屬於自己的對象,關於這個可以看前面的部落格。
public class ThisTest { private int a; private int b; public int Add() { return a + b; } public void SetA(int a) { this.a = a; } public void SetB(int b) { this.b = b; } }
function Add(x, y) { var a = x; var b = y; this.SetA = function (a) { a = a; } this.SetB = function (b) { b = b } this.GetAdd = function () { return a + b; }}var Test = new Add(3, 7)alert(Test.GetAdd())
上面這兩段代碼是用C#和Javascript做了一個對比,Javascript中沒有類,沒有共有變數,也就是public等,而只有全域變數和私人變數,但是Javascript可以通過閉包去類比,函數中的var定義的變數在函數執行完畢後在外部是不能訪問的,但是通過返回一個內部的函數就可以了,或者通過this這個關鍵字去訪問,this這個在函數訪問的時候就是window,而用new執行個體化對象的時候這個this就是當前new的這個對象,通過this,就可以在外面訪裡面的函數,可以將這個稱作為“成員變數或者成員函數”,當然這個說法只是我一廂情願而已,真正的Javascript中是不存在的,在這裡只是和C#做了個比較而已。
var str = "2"; Object.prototype.str = "1"; (function Test() { alert(str); })();
上面這個是用自執行函數寫的,自執行函數其本質是一個匿名函數,為什麼叫這個名稱,我沒自己深究,大膽猜測下,因為這個函數是可以自動執行的,回想一般的函數,分兩個步驟:
1,定義;
2,調用。
這裡將兩個步驟合二為一了,可以認為是下面的寫法:
var FunctionTest = function Test() { alert(str); } FunctionTest();
人有的時候需要大膽猜測,然後去證明或者澄清,這不失為一種學習和自我理解的方法,這個錯對不予考究,到此為止,因為這個例子在這裡不是用來說這個的。
上面的結果是2,這說明了window的範圍靠近函數的範圍,而Object原型的範圍稍遠,當然你可以刪除var 這一行,代碼也是可以啟動並執行。我們可以得出這樣一個順序,Object.Prototype-window-函數,這也是搜尋變數的順序。
var str = "2"; Object.prototype.str = "1"; Object.str = "3"; (function Test() { alert(str); })();
這個經過測試,順序是Object-Object.Prototype-window
window.str = "4"; Object.prototype.str = "1"; Object.str = "3"; var str = "2"; (function Test() { alert(str); })();
這個例子的順序是object-object.Prototype-window-var所定義的,這是因為變數覆蓋的原因,因為Javascript在先行編譯階段確定變數,如果定義了兩個,那麼只會用最後一個,大家可以將var 和window的這個反過來試試。
最後推薦一個部落格:http://www.cnblogs.com/rubylouvre/archive/2009/08/08/1541914.html