關於構造函數和原型prototype對象的理解
構造函數
1.什麽是構造函數
構造函數,主要用於對象創建的初始化,和new運算符一起用於創建對象,一個類可以有多個構造函數,因為函數名相同,所以只能通過參數的個數和類型不同進行區分,即構造函數的重構, 如果沒有定義構造函數,那麽該類會自動生成一個空參數的構造函數。
在javascript中,對象創建有二種方式:對象字面量和使用new表達式。
對象字面量,每創建一個對象都要重新定義一次語句,不便於創建大量相同類型的對象
new表達式,配合構造函數使用,例如var person1 = new Person("wmm",30);
new操作符調用構造函數執行了以下幾步:
a.首先創建一個空的person1對象 ------ var person1 = {};
b.將空對象person1的__proto__屬性(其原型)指向構造函數的prototype對象, ------ person1.__proto__ = Person.prototype;
c.將構造函數的作用域賦值給person1對象,Person內的this指向實例化對象person1, -------- Person.call(person1);
d.返回新對象person1。 ------ return person1
2.構造函數和普通函數的區別
a.函數名稱格式,構造函數一般首字母大寫,而普通函數是一般首字母小寫,使用駝峰式命名;
b.是否需要new調用, 構造函數需要new操作符調用,普通函數不需要;
c.this的指向,構造函數裏this指向實例化對象,普通函數中this指向調用函數的對象,沒對象調用時,默認指向window
d.返回值,構造函數默認返回值為實例化對象,不用return返回值,而普通函數通過return語句返回值。
prototype對象
每一個函數都有一個prototype屬性,它指向一個對象的引用,每個實例化對象會從prototype指向的對象上繼承
每一個對象都會在內部初始化一個屬性(__prototype__),屬性__proto__所指向的對象是它的原型對象,即
person1.__proto__ === Person.prototype。
當我們訪問一個對象的屬性時,如果對象內部找不到該屬性,就會去實例化對象的屬性__proto__指向的對象裏面去找這個屬性,__proto__裏面有它自己的__proto__ 屬性,然後一直找下去,直到找到為止。如果直到最頂層的Object.prototype還是找不到,則返回undefined.
所有一切對象的原型頂端,都是Object.prototype,Object.prototype的原型對象為null ,null對象沒有自己的原型。
function Person(name){ this.name = name; this.eat = function(){ console.log("food") } }
Person.prototype.age = "20";
Person.prototype.height = function(){
this.h = "160";
console.log(this.h);
} var person1 = new Person("吳默默"); var person2 = new Person("wumomo");
每個實例化對象會繼承構造函數的原型對象,實例化對象的屬性__proto__指向的是原型對象,所以person1.__proto__ === person2.__proto__ === Person.prototype
prototype對象除了自定義屬性和__proto__屬性外,還有一個constructor屬性,constructor屬性指向的是它所在的構造函數,如下圖:
實例化對象本身其實沒有constructor屬性,當找不到constructor屬性時,就會根據person1.__proto__ 在其原型對象上查找。所以 person1.constructor === person1.__proto__.constructor === Person.prototype.constructor === Person
當重新定義prototype對象時,prototype對象原有的constructor屬性會丟失,其constuctor屬性會默認為Object(Person.prototype.constructor === Object)
構造函數和原型prototype的區別
每創建一個實例化對象,都要調用一次構造函數,當創建多個實例化方法時,就要調用多次構造函數,這可能會導致內存溢出,性能較差,而實例化對象會繼承prototype對象上的屬性,使用原型prototype定義時,不管實例化多少個對象,都只調用一次,所以最好的解決方式是公共的方法和屬性可以放在prototype原型中,其他的放在構造函數內。
擴展:
isPrototypeOf() ----- 用於測試一個對象是否存在於另一個對象的原型鏈上
Person.prototype.isPrototypeOf(person1) // ture
instanceof ----- 一個對象是否是這個特定類或者是它的子類的一個實例,形式為 object instanceOf constructor
person1 instanceof Person // true
person3 instanceof Person // false
in運算符和hasOwnProperty() ------ 都是用來檢測對象中是否存在某屬性
in運算符 :只要通過對象能訪問到屬性就返回true,否則返回false
hasOwnProperty() : 只能檢測到對象本身的屬性,無法檢查其原型鏈中是否具有該屬性。
關於構造函數和原型prototype對象的理解