概述 在JavaScript中,我們可以使用函數、數組、對象,以及日期、正則等一些內置類型的實例,它們都是複雜類型的表現。從本質上講,這些複雜類型都是Object類型。本篇主要的內容有3點:函數、數組和對象。 函數 函數是JavaScript的一大重點,它非常的靈活。不像C#這種強類型語言,可以顯式... ...
概述
在JavaScript中,我們可以使用函數、數組、對象,以及日期、正則等一些內置類型的實例,它們都是複雜類型的表現。從本質上講,這些複雜類型都是Object類型。本篇將主要介紹三種Object類型的體現:函數、數組和對象。
函數
函數是JavaScript的一大重點,它非常的靈活。不像C#這種強類型語言,可以顯式地聲明"class",JavaScript沒有"class"的概念,但藉助函數我們可以實現"class"的概念。類和對象是面向對象編程的基礎,所以掌握函數是掌握JavaScript面向對象編程的前提。
定義函數
JavaScript的函數有兩種定義方式:函數聲明和表達式聲明。
方式1:函數聲明
// 函數聲明 function sum(a,b){ return a + b; } var result = sum(3,5); // 8;
函數聲明:function
關鍵字後面跟著函數名稱,參數放在一對小括弧中,函數內容放在大括弧內。
這段代碼中,sum
是函數的名稱,如果指定了return語句,則可以通過變數來接收。
方式2:表達式聲明
// 表達式聲明 var hello = function(){ console.log('Hello!'); } hello();
表達式聲明:function
關鍵字後面沒有函數名稱,這種函數也被稱作匿名函數,匿名函數通常會被一個變數引用。
這段代碼中,hello
不是函數的名稱,它是一個指向匿名函數的指針變數。
函數可以沒有return語句,這時JavaScript引擎會自動地返回一個undefined。
兩種方式的區別
雖然這兩種方式比較相似,但它們有一個較大的區別——聲明的提升。
使用方式1聲明的函數會被會被提升至函數所處上下文的頂部,使用方式2則不會。
下麵這段代碼在瀏覽器中是可以工作的,並且不會報錯。
var result = sum(3,5); // 8; // JavaScript引擎將函數聲明提升到頂部 function sum(a,b){ return a + b; }
上面這段代碼會被JavaScript引擎解釋為下麵這段代碼。
function sum(a,b){ return a + b; } var result = sum(3,5); // 8;
使用表達式聲明的函數不會被提升,下麵這段代碼會報錯。
// 會報錯:hello is not a function hello(); var hello = function(){ consol.log('Hello!'); }
函數聲明使得JavaScript引擎提前獲知了函數的名稱,匿名函數由於沒有名稱,JavaScript引擎無法對它進行提升。
小提示:無論使用哪種方式,應該先聲明函數再使用,這樣才不會出錯。
函數的類型
使用typeof查看函數的類型時,得到的結果是"function"。
在JavaScript中,函數是一種特殊的引用類型,所有非函數的引用類型使用typeof都會返回"object"。
之前提到了JavaScript只有一種複雜類型(引用類型)——Object類型,函數既然是引用類型,那麼怎麼證明他是屬於Object類型的呢?
使用instanceof操作符
雖然JavaScript沒有類的概念,但是它有構造函數的概念,JavaScript是通過構造函數來創建對象實例的。
instanceof操作符可以用來判斷某個構造函數的prototype屬性所指向的對象是否存在於另外一個要檢測對象的原型鏈上。
後面的文章會講到prototype和原型鏈,如果你不理解這句話,則可以將這個操作符看成C#中的is操作符(判斷對象是否為某個類的實例)。
下麵這幅圖揭示了sum函數是Function的實例,Function又是Object的實例,sum也是Object的實例。
Function()和Object()是JavaScript內置的兩個構造函數。
sum()函數同樣可以通過Function()函數來實現:
var sum = new Function('a','b', 'return a + b;');
Function()構造函數的前面幾個參數都表示函數的參數,最後一個參數表示函數的內容。
不管是函數參數還是函數內容,都是用字元串表示的,JavaScript引擎在運行時才需要先解析這種方式聲明的函數,才能確定其形式。
雖然Function()構造函數可用於創建函數,但不建議這麼做,因為它會使代碼難以理解和調試。
小提示:在JavaScript中,new後面接的肯定是一個構造函數,例如new Function()、new Object()。
函數的本質是數據
函數本質上是數據,這是一個比較重要的概念。
函數可以用表達式聲明,並將其賦給一個變數。
變數用於存儲數據,變數要麼存儲基礎類型的值,要麼存儲引用類型的地址。
下麵這段代碼,sum是一個變數,存儲的卻是函數指針。
同時,這個匿名函數被當成一般的值,並賦給了變數add。
var sum = function (a, b) { return a + b; }; var add = sum; add(6,4); // 10
JavaScript的函數就是數據,但它們是一種特殊的數據:
- 包含代碼
- 這些代碼可以被執行或被調用
對象
使用基礎類型時,我們只能一個變數存儲一個值,如果要將多個值存儲在一個變數中,可以使用對象。
JavaScript中的對象是動態的,對象中包含屬性,屬性以key-value形式存在。
由於JavaScript的靈活性,使得我們可以為在任意地方指定對象的屬性,對象的屬性也可以被指定為任意類型。
創建對象
在使用對象前,我們應該先創建對象。
對象有兩種創建方式:使用{}
或Object()
構造函數。
// 方式1:使用{}創建對象 var person = { name: 'keepfool', job: 'developer', say: function() { return 'Hello! I am ' + this.name + ', I am a ' + this.job; } }; // 方式2:使用Object()構造函數 var player = new Object(); player.name = 'Stephen Cury'; player.age = 28; player.play = function() { return 'I am ' + this.name + ', ' + this.age + ' years old, I play basketball very well!'; }
這兩種方式本質上沒有什麼區別,使用方式1聲明對象時,JavaScript引擎背後做的工作和new Object()是一樣的。
方式1相當於方式2的快捷方式,建議使用方式1來創建。
在對象初始化後,你可以在任意時間給對象追加新的屬性。
// 方式1:使用{}創建對象 var person = { name: 'keepfool', job: 'developer', say: function() { return 'Hello! I am ' + this.name + ', I am a ' + this.job; } }; // 追加新的屬性 person.weigh = '70kg'; person.run = function() { return 'I am running!'; }
註意:person對象的say屬性是一個函數,當函數作為對象的一個屬性時,我們稱之為“方法”。
對象的屬性就是數據,JavaScript的屬性可以是方法,方法本質上是函數,從這個層面又印證了“函數就是數據”的說法。
say方法中用到了this,this是一個指針,它指向person對象本身,this.name即person.name。
訪問屬性
訪問對象屬性的方式也有兩種:使用object.property
和object['property']
。
object.property
方式:
object['property']
方式:
註意:person的say屬性和player的play屬性都是方法,通過person.say和player.play得到的是方法的指針(函數的指針),使用()才是調用對象的方法。
由於數組也提供了[]
方式訪問元素,為了區分數組和對象,建議使用object.property
方式訪問屬性。
對象的類型
使用typeof查看對象的類型,得到的結果都是"object"。
使用instanceof檢測是否為Object類型,得到的結果都是true。
數組
在C#中,數組中的元素是同一個類型的,JavaScript則不然。
在JavaScript中,你可以在數組中存儲任意類型的值,數組元素可以是數字、字元、日期、對象、數組等等。
這和C#中的ArrayList有些相似。
創建數組
在JavaScript中,創建數組有兩種方式:
// 方式1:使用[]創建數組 var arr1 = [1,"Hello", true, {id : 1, name : "keepfool"}]; // 方式2:使用Array()構造函數創建數組 var arr2 = new Array(1, "Hello", true, {id : 1, name : "keepfool"});
方式1和方式2本質上是一樣的,在使用方式1聲明數組時,JavaScript引擎做的事情和new Array()也是一樣的。
方式1比方式2更加便捷直觀一些,建議使用方式1。
訪問數組元素
數組是一個有序的數據集合,通過[]
索引器可以訪問數組元素。
數組的類型
使用typeof查看數組的類型時,得到的結果是"object"。
數組的檢測
如果你定義了多個變數,有些變數用於表示數組,有些變數用於表示數組。
將typeof操作符應用於對象或數組變數,得到的結果都是"object"。
我們怎麼區別哪個變數是對象,哪個變數時數組呢?有兩種方式可以鑒別。
方式1:使用instanceof
方式2:使用isArray()方法
數組是否為Object?
instanceof操作符檢測函數的類型是Object的,那麼數組也可以用這種方式來檢測。
所以數組本質上也是Object類型的。
複雜類型總結
- 函數、對象和數組都是Object類型的實例,使用Instanceof操作符可以檢測它們
- 函數的本質是數據,function是Function的實例,Function又是Object的實例
- 對象是由屬性構成的,對象的屬性可以是任意類型的
- 數組是有序的數據集合,數組元素可以是任意類型的,Array是Object的實例