一步步了解構造函數
一、關於對象
在了解構造函數之前,我們需要先了解下對象,我們都聽說面向對象編程,那麽這當中的對象是什麽,簡單來說,對象是個功能模塊,這個功能可以接收信息,處理信息和發送信息。從我們代碼的角度看,對象是一個封裝了屬性和方法的容器,屬性是對象的狀態,方法則是對象的行為(完成某種任務)。我們可以用這個對象對現實生活中的實物進行抽象描述,比如,我們把飛機看做對象,那麽可以使用“屬性”記錄具體是哪種機型,同時使用“方法”表示飛機的表現行為,是起飛、飛行中還是降落等。緊接著,我們把飛行員看做對象。使用“屬性”記錄飛行員的信息,使用“方法”表示飛行員對飛機的操作,那麽飛行員對飛機的操作、飛機的表現行為之間構成的關系,可以抽象為兩個對象之間的關系,這種用代碼對象模擬現實情況的操作,就是面向對象編程。
二、什麽是構造函數
使用面向對象編程,第一步就是要創造對象,在js中,構造函數是創建對象的方式之一,構造函數(簡稱constructor)其實就是一個普通函數的升級版函數,區別於普通函數就在於用法不同,構造函數是可以提供模板,用來生成多個對象的函數,你也可以理解為,一個普通函數可以被多次使用生成不同的對象,那麽這個普通函數就是構造函數,在寫法上,為了容易辨認構造函數,構造函數名字的第一個字母通常大寫,構造函數中必定存在this,普通函數也可以存在this,this指向Window全局。一個簡單的構造函數如下:
var i = 0
function Plane (type) {this.type = type this.state = function () { console.log(type + ‘起飛‘) }
i ++
console.log(i)
console.log(this) }
Plane() // Window {postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window, …};type與state是Window對象的一個屬性方法
三、為什麽要使用構造函數
構造函數是可以提供模板,用來生成多個對象的函數,對一個新創建的對象進行初始化,可以減少我們許多重復的代碼,比如要創建許多種飛機的對象,我們可以通過構造函數先初始所有飛機共用的屬性和行為表現,之後傳值調用構造函數即可,無需每個飛機種類都去聲明一個對象。
四、如何使用構造函數
直接調用構造函數,則相當於是調用一個普通函數,要使構造函數得到復用,則需要結合new,通過new調用構造函數來實例化創建新的對象,比如創建波音飛機和梟龍戰機的對象,調用上述構造函數,為:
var boyin = new Plane(‘波音‘); // 構造函數執行一遍,輸出 Plane {type: "波音", state: ?},1
boyin.state(); // 波音起飛
var xiaolong = new Plane(‘梟龍‘) // 構造函數再執行一遍,輸出 Plane {type: "梟龍", state: ?},2
xiaolong.state(); // 梟龍起飛
五、為什麽new可以實現調用構造函數實例化創建新的對象
通過new調用構造函數來實例化創建新的對象,這個過程中,發生了一下五個步驟:
1、建立一個名為變量的空變量
2、將新對象的_proto_屬性指向構造函數的prototype原型
3、將構造函數中的this指向新對象
4、執行一遍構造函數中的代碼
如果使用代碼來模擬這個過程,如下:
new Plane("波音") = { var obj= {}; // 聲明空對象 obj.__proto__ = Plane.prototype; // 設置對象的_proto_屬性來鏈接到函數的prototype屬性 var result = Plane.call(obj,"波音"); // 通過call改變this指向,同時執行Plane方法和傳值 return typeof result === ‘object‘? result : obj; // 將結果返回 }
其中,關於obj._proto_ = Plane.prototype,是設置對象的_proto_屬性來鏈接到函數的prototype屬性,當我們訪問新構建的對象的屬性和方法時,會先在構造函數上找,找不到就沿著原型鏈向上追溯。
在這裏可以說下關於_proto_和prototype。
_proto_是一個對象擁有的內置屬性(請註意:每個對象都有一個_proto_屬性,_proto_是對象的內置屬性),是JS內部繼承和使用構造函數以及尋找函數原型鏈上的屬性和方法的屬性。
prototype是函數的一個屬性((請註意:每個函數都有一個prototype屬性,prototype是函數的內置屬性),這個屬性是一個指針,指向一個對象。這個對象你可以理解為包含構造函數以及其原型上的屬性和方法,同時包含其他內容的大對象。有趣的是,prototype是個對象,也具有_proto_
回歸obj._proto_ = Plane.prototype,從上面打印出來的a對象的_proto_以及b函數的prototype,可以看出共同擁有constructor屬性,每一個對象實例都可以通過 constrcutor 對象訪問它的構造函數,因此obj._proto_ = Plane.prototype就將obj對象與Plane函數關聯起來了。擁有了Plane函數的屬性和方法。
我們在構造函數Plane的原型上添加屬性和方法,在new實例化後通過對象訪問,結果對象是能訪問到的:
六、多用途構造函數,關於構造函數中的return
一個構造函數內部使用了return,就可以成為一個多用途構造函數,具體可看下例子:
function C2(a, b){ this.p = a + b; this.alertP = function(){ alert(this.p); } return this.p;//此返回語句在C2作為構造函數時沒有意義 } var c2 = new C2(2,3); c2.alertP();//結果為5 alert(C2(2, 3)); //結果為5
構造函數中如果加入了return的話,需要註意分兩種情況
1. return的是五種簡單數據類型:String,Number,Boolean,Null,Undefined,則new實例化構造函數時,return回來的是空對象
2、如果return的是對象,則new實例化構造函數時,return回來的是對象
一步步了解構造函數