js高階建構函式,例項物件和原型物件——prototype、__proto__和constructor構造器
一、前言
瞭解JavaScript面向物件,需要先了解三個名詞: 建構函式,例項物件和原型物件。
注意:JavaScript中沒有類(class)的概念,取而代之的是建構函式,兩者類似卻又有很大的差別。
先上程式碼,最常用的:
function Person(name, age) { this.name = name; this.age = age; this.eat= function() { alert('吃西紅柿') } } var person1 = new Person('小米', 28); var person2 = new Person('大米', 23);
Chrome列印測試,上圖:
上圖分別是:
- 圖一列印perspn1例項物件,
- 圖二列印Person建構函式,
- 圖三列印建構函式的prototype(即Person的原型物件)和person1的__proto__
通過上面的列印,我們可以發現幾個問題:
- 例項物件和建構函式一點也不像,
- person1.__proto__和Person.prototype一模一樣
我們先來看看第一個問題:例項物件和它的建構函式——打印出來的內容一點也不像
這個問題就大了呀!
我們都知道,在java中,類和它的例項物件之間有很緊密的關係,你的(屬性和方法)是我的,我的還是我的!
可是到了js這裡,Person建構函式中並沒有體現出他本該有的屬性和方法
也就是說,無論我們例項化出來多少個person,他們的屬性和方法都是不一樣的。屬性不一樣還可以理解,方法不一樣就意味著:每個例項出來的person的方法並不是共用的(並不指向同一個地址空間),那我們要建構函式還有什麼意義?
我們要的還是類和例項物件的關係那樣,能夠共享資料,節省記憶體空間
這就引出了我們今天要講的關鍵:原型
二、正文
(一)、使用原型物件造共用屬性和方法
前面已經講到,js的建構函式和例項物件之間,並不能夠實現共享資料,節省記憶體空間的作用,所以我們就引入了原型
再上程式碼:這次我們添加了原型方法play()
//建構函式
function Person(name, age) {
this.name = name;
this.age = age;
this.eat= function() { alert('吃西紅柿') }
}
//新增原型方法
Person.prototype.play = function() { alert("玩溜溜球")}
//例項化物件
var person1 = new Person('小米', 28);
var person2 = new Person('大米', 23);
在僅限Chrome測試:
上圖分別是:
- 圖一列印perspn1例項物件,
- 圖二列印Person建構函式,
- 圖三列印建構函式的prototype(即Person的原型物件)和person1的__proto__
通過上圖可以知道:建構函式中定義的方法,例項化後並不一樣,而原型物件prototype中定義的方法確實相等的(指向同一地址)
添加了原型方法後,例項物件person1和建構函式Person上並沒有直觀體現,反而在Person.prototype和person1.__proto__中顯示了出來
由此,我們可以知道,JS中給同一建構函式的例項物件 新增共用屬性和方法,需要使用prototype這一屬性,也就是原型物件來實現
(二)、prototype和__proto__和constructor構造器
上圖表現出:Person.prototype === person1.__proto__
即:例項物件的__proto__和建構函式的prototype相等(指向同一地址),完全一樣
上圖,圖一列印Person.prototype;圖二列印person1.__proto__;圖三列印Person建構函式
通過上面三張圖,我們可以發現:Person.prototype.constructor和person1.__proto__.constructor以及Person一模一樣
上圖表現出:Person.prototype.constructor === Person
即:建構函式的原型物件(prototype)的構造器(constructor)指向該建構函式
通過之前的列印和上圖,我們可以發現,
- 例項物件中都有__proto__屬性,而建構函式中都有prototype屬性,
- prototype和__proto__都有構造器constructor,其實例項物件的__proto__和建構函式的prototype是一樣的(Person.prototype === person1.__proto__)
- 建構函式的原型物件(prototype)的構造器(constructor)指向該建構函式(Person.prototype.constructor === Person)
(三)、使用原型的注意事項
原型屬性和方法統一定義時,需要定義構造器constructor,即將建構函式的原型物件中的構造器指向該建構函式,否則原型屬性和方法定義失敗
//新增原型方法
Person.prototype.job= "程式設計師"
Person.prototype.address = "蘇州"
Person.prototype.study= function() { alert("學JavaScript")}
//可以這樣定義嗎?
Person.prototype = {
job: "程式設計師",
address: "蘇州" ,
study: function() { alert("學JavaScript")}
}
//上面的原型物件定義出錯,需要加上constructor--手動修改構造器的指向
Person.prototype = {
constructor: Person
job: "程式設計師",
address: "蘇州" ,
study: function() { alert("學JavaScript")}
}
分別將兩種新增原型屬性和方法的方式列印看看:
上圖分別是:
- 圖一為錯誤示範,表示未手動修改構造器指向,結果列印顯示Person.prototype丟失構造器constructor,被新新增的物件覆蓋
- 圖二為正確示範,表示手動修改構造器指向,即加上constructor: Person,
三、結束
加油哦,最後來張圖