玩轉JavaScript OOP[1]——復雜類型


概述

在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"。

image

之前提到了JavaScript只有一種復雜類型(引用類型)——Object類型,函數既然是引用類型,那么怎么證明他是屬於Object類型的呢?

使用instanceof操作符

雖然JavaScript沒有類的概念,但是它有構造函數的概念,JavaScript是通過構造函數來創建對象實例的。
instanceof操作符可以用來判斷某個構造函數的prototype屬性所指向的對象是否存在於另外一個要檢測對象的原型鏈上。
后面的文章會講到prototype和原型鏈,如果你不理解這句話,則可以將這個操作符看成C#中的is操作符(判斷對象是否為某個類的實例)。

下面這幅圖揭示了sum函數是Function的實例,Function又是Object的實例,sum也是Object的實例。

image
Function()和Object()是JavaScript內置的兩個構造函數。

sum()函數同樣可以通過Function()函數來實現:

var sum = new Function('a','b', 'return a + b;');

image

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.propertyobject['property']

object.property方式:

image

object['property']方式:

image

注意:person的say屬性和player的play屬性都是方法,通過person.say和player.play得到的是方法的指針(函數的指針),使用()才是調用對象的方法。
由於數組也提供了[]方式訪問元素,為了區分數組和對象,建議使用object.property方式訪問屬性。

對象的類型

使用typeof查看對象的類型,得到的結果都是"object"。

image

使用instanceof檢測是否為Object類型,得到的結果都是true。

image

 

數組

在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。

訪問數組元素

數組是一個有序的數據集合,通過[]索引器可以訪問數組元素。

image

數組的類型

使用typeof查看數組的類型時,得到的結果是"object"。

image

數組的檢測

如果你定義了多個變量,有些變量用於表示對象,有些變量用於表示數組。
將typeof操作符應用於對象或數組變量,得到的結果都是"object"。
我們怎么區別哪個變量是對象,哪個變量時數組呢?有兩種方式可以鑒別。

方式1:使用instanceof

image


方式2:使用isArray()方法

image

數組是否為Object?

instanceof操作符檢測函數的類型是Object的,那么數組也可以用這種方式來檢測。

image

所以數組本質上也是Object類型的。

復雜類型總結

  • 函數、對象和數組都是Object類型的實例,使用Instanceof操作符可以檢測它們
  • 函數的本質是數據,function是Function的實例,Function又是Object的實例
  • 對象是由屬性構成的,對象的屬性可以是任意類型的
  • 數組是有序的數據集合,數組元素可以是任意類型的,Array是Object的實例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM