JavaScript建構函式與原型之間的聯絡
目錄
- 一、建構函式和原型
- 1、建構函式
- 2、建構函式的問題
- 3、建構函式原型 prototype
- 4、物件原型 __proto__
- 5、constructor 建構函式
- 6、建構函式、例項、原型物件三者之間的關係
- 7、 的成員查詢機制(規則)
- 8、 擴充套件內建物件
- 二、類的本質
一、建構函式和原型
1、建構函式
建構函式是一種特殊的函式,主要用來初始化物件,即為物件成員變數賦初始值,它總與 new
一起使用。我們可以把物件中一些公共的屬性和方法抽取出來,然後封裝到這個函式裡面。
在 中,
使用建構函式時要注意以下兩點:
- 建構函式用於建立某一類物件,其首字母要大寫。
- 建構函式要和
new
一起使用才有意義。
new 在執行時會做四件事情:
- 在記憶體中建立一個新的空物件。
- 讓 this 指向這個新的物件。
- 執行建構函式裡面的程式碼,給這個新物件新增屬性和方法。
- 返回這個新物件(所以建構函式裡面不需要
return
)。
Script
的建構函式中可以新增一些成員,可以在建構函式本身上新增,也可以在建構函式內部的 this 上新增。通過這兩種方式新增的成員,就分別稱為靜態成員和例項成員。
例項成員:在建構函式內部建立的物件成員稱為例項成員,只能由例項化的物件來訪問。
靜態成員:在建構函式本上新增的成員稱為靜態成員,只能由建構函式本身來訪問 。
例如:
function A(uname,age){ this.uname = uname; this.age = age; this.say = function() { console.log(this.uname+'你好'); } } var wh = new A('王歡',18); var xl = new A('小熊',18);
在上述程式碼中,建構函式中通過this新增的name
,age
,say
如:建立一個靜態成員。
A.sex='女';
2、建構函式的問題
建構函式方法很好用,但是存在浪費記憶體的問題
如下所示:
function Student(age,name){ this.age = age; this.name = name; this.score = function(){ console.log('孩子們成績都很好!'); } } console.dir(Student); var xl = new Student(18,'小熊'); var wh = new Student(17,'王歡'); xl.score(); wh.score();
通過下述程式碼判斷兩次呼叫的方法是否地址相同。
console.log(xl.score === wh.score);
列印結果為:
可知兩次呼叫A內部的say函式,地址並不相同,是因為開闢兩個記憶體空間,導致浪費記憶體。
3、建構函式原型 prototype
建構函式通過原型分配的函式是所有物件所共享的。JavaScript 規定,每一個建構函式都有一個 prototype
屬性,指向另一個物件。注意這個 prototype
就是一個物件,這個物件的所有屬性和方法,都會被建構函式所擁有。
如下所示,創www.cppcns.com建一個建構函式:
function Student(age,name){ this.age = age; this.name = name; this.score = function(){ console.log('孩子們成績都很好!'); } } console.dir(Student);
列印該建構函式裡面所有的方法,可知:
可以找到 prototype
物件。
可以把那些不變的方法,直接定義在prototype
物件上,這樣所有物件的例項就可以共享這些方法。
function Student(age,name){ this.age = age; this.name = name; } Student.prototype.score = function(){ console.log('孩子們成績都很好!'); } console.dir(Student); var xl = new Student(18,'王歡'); xl.score(); wh.score(); console.log(xl.score === wh.score);
列印結果為:
並且兩次呼叫函式只開闢了一個記憶體空間,也減少了記憶體的浪費。
注意:一般情況下,公共屬性定義到建構函式裡面,公共方法定義到原型物件身上。
4、物件原型 __proto__
物件都會有一個屬性__proto__
指向建構函式的 prototype
原型物件,之所以我們物件可以使用建構函式prototype原型物件的屬性和方法,就是因為物件有 __proto__
原型的存在。
如下所示:
function Student(age,name){ this.age = age; this.name = name; } Student.prototype.score = function(){ console.log('孩子們成績都很好!'); } // console.dir(Student); var xl = new Student(18,'小熊'); var wh = new Student(17,'王歡'); console.log(xl);
通過以下程式碼名看其是否具有__proto__
物件原型
console.log(xl);//物件身上系統自己新增一個__proto__屬性指向建構函式的原型物件
輸出結果為:
可知存在。
在上述例子中輸入下述程式碼判斷__proto__
物件原型和原型物件prototype
是否等價。
console.log(xl.__proto__ === Student.prototype);
列印結果為:true
故: __proto__
物件原型和原型物件prototype
是等價的
通過例項物件呼叫score函式,如下所示:
xl.score();
輸出結果為:
可以呼叫,其方法查詢規則是:首先看看xl物件身上是否有score
方法,如果有,則執行這個物件上的score
,如果沒有該方法,因為有__prooto__
屬性的存在,就去建構函式原型物件 prototype
身上去查詢。
可用下圖描述:
__proto__
物件原型的意義就在於為物件的查詢機制提供一個方向,或者說一條路線,但是它是一個非標準屬性,因此實際開發中,不可以使用這個屬性,它只是內部指向原型物件 prototype
5、constructor 建構函式
根據前面的例子,分別列印例項物件(Student
)的物件原型( __proto__)和建構函式(xl)(prototype
)原型物件
console.log(Student.prototype); console.log(xl.__proto__);
列印結果為:
可知:物件原型( __proto__)和建構函式(prototype)原型物件裡面都有一個屬性 constructor 屬性 ,constructor
我們稱為建構函式,因為它指回建構函式本身。
再分別列印物件原型和建構函式原型的constroctor
屬性。觀察其返回值。
console.log(Student.prototype.constructor); console.log(xl.__proto__.constructor);
列印結果為:
可知他們均指向Student
建構函式。
即constructor
主要用於記錄該物件引用於哪個建構函式,它可以讓原型物件重新指向原來的建構函式。
一般情況下,物件的方法都在建構函式的原型物件中設定。當給建構函式新增多個方法時,可以採用物件的方式,
如下所示:
Student.prototype = { score: function(){ console.log('孩子們成績都很好!')},study: funchttp://www.cppcns.comtion(){ console.log('好好學習!'); }
當列印修改後的原型物件的consructor屬性時:
發現原型物件的指向發生變化,這是因為給原型物件採取物件形式賦值,這樣就會覆蓋建構函式原型物件原來的內容,這樣修改後的原型物件constructor
就不再指向當前構造函數了。
此時,我們可以在修改後的原型物件中,新增一個 constructor
指向原來的建構函式。
如下:
Student.prototype = { constructor:Student,score: function(){ console.log('孩子們成績都很好!')},study: function(){ console.log('好好學習!'); }
最後,列印的結果為:
成功指回原建構函式。
6、建構函式、例項、原型物件三者之間的關係
根據上例:建構函式、例項、原型物件三者之間的關係可用下圖描述:
7、JavaScript 的成員查詢機制(規則)
- 當訪問一個物件的屬性(包括方法)時,首先查詢這個物件自身http://www.cppcns.com有沒有該屬性。
- 如果沒有就查詢它的原型(也就是 __proto__指向的
prototype
原型物件)。 - 如果還沒有就查詢原型物件的原型(Object的原型物件)。
依此類推一直找到 Object
為止(null)。
__proto__物件原型的意義就在於為物件成員查詢機制提供一個方向,或者說一條路線。
8、 擴充套件內建物件
可以通過原型物件,對原來的內建物件進行擴充套件自定義的方法。
首先列印陣列的原型物件,檢視有哪些內建物件。
客棧 console.log(Array.prototype);
列印結果為:
例如現在給陣列增加自定義求偶數和的功能。
Array.prototype.sum = function(){ var sum = 0; for(var i=0;i<this.length;i++){ sum += this[i]; } return sum; }
檢查內建物件是否擴充套件成功,再次輸入:
console.log(Array.prototype);
構建成功,在給一個具體的例項物件,判斷是否可以正常使用:
var arr = [1,2,3]; console.log(arr.sum());
列印結果為:
二、類的本質
class
本質還是function
.- 類的所有方法都定義在類的
prototype
屬性上 - 類建立的例項,裡面也有__proto__ 指向類的prototype原型物件
- ES6的類它的絕大部分功能,ES5都可以做到,新的
class
寫法只是讓物件原型的寫法更加清晰、更像面向物件程式設計的語法而已。
到此這篇關於JavaScript建構函式與原型的文章就介紹到這了,更多相關JavaScript建構函式、原型內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!