JavaScript對象創建與繼承總結

JavaScript中的每個元素都是一個對象,都繼承自Object對象,因此可以說Object是JavaScript的根對象。首先說說JavaScript中創建對象的幾種常見方式:
1、對象字面量創建對象,如:

var myObject = {
    name: '張三',
    sex: '男',
    age: 25
}
//等價於 
var myObject = new Object();
myObject.name = '張三';
myObject.sex = '男';
myObject.age = 25;
//還有常見的定義一個數組
var arr = [];//等價於 var arr = new Array();

2、利用JavaScript內嵌的引用類型創建相關對象,如:

var arr = new Array(5)
var arr = new Array("red", "blue");
/*數組長度爲5,注意:JavaScript中數組的長度不是固定的,可以動態改變,數組長度length只是在某個狀態下的一個動態值*/

var date = new Date();
var pattern = new RegExp("[bc]at", "i");

3.1、自定義構造函數創建對象(構造函數模式),如:

//構造函數首字母一般大寫
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        console.log(this.name);
    };
}
var person = new Person("kitty", 25, "Software Engineer");
//構造函數模式創建對象的缺陷:每個實例對象均有一套自己專屬的屬性和方法,定義實現同一功能的多個方法顯然是一種浪費內存的做法。於是想到把屬性和方法定義在構造函數的原型對象中,見方法3.2

在說原型模式之前,先簡要介紹一下原型:任何函數在創建的時候,都會包含一個原型屬性prototype,指向一個原型對象。初始狀態下,原型對象都只包含一個構造函數屬性constructor,指向創建此函數的構造函數(一般是Function)。
實例對象與構造函數原型對象的關係:當調用構造函數創建一個實例對象後,該實例內部包含一個指針[[Prototype]],指向構造函數的原型對象,可通過實例的proto屬性訪問原型對象。
實例對象調用方法:先在實例對象中查找該方法,當實例對象中不存在該方法時,到原型對象中查找,找到,執行。如果存在原型鏈,會沿着原型鏈以此查找,例如 toString()方法

alert(Person.prototype.isPrototypeOf(person));//true
alert(Object.getPrototypeOf(person)==Person.prototype);//true

3.2、原型模式
所謂原型模式,就是把對象屬性和方法都定義在構造函數的原型對象中,避免每個對象都重複定義屬性和方法,如:

//空構造函數
function Person(){
}
//把對象屬性和方法都定義在原型對象中
Person.prototype.name = "kitty";
Person.prototype.age = 25;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
}

var person = new Person();
//原型模式創建對象的缺陷:雖然克服了重複定義多個相同功能函數的缺陷,但也帶來新的缺陷,即多個實例對象共享一套屬性和方法,只要一個其中實例對象修改屬性值,其他的實例對象中的屬性值也會被修改。

//綜合構造函數模式和原型模式,即對象屬性定義在構造函數中,方法定義在構造函數的原型對象中
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype.sayName = function(){
    alert(this.name);
}
var person1 = new Person("kitty", 25, "Software Engineer");
var person2 = new Person("hello", 25, "Software Engineer");
//此時實例對象person1和person2中的屬性互不干擾,公用sayName方法。***這是最常用的創建對象的方法***

最常見、最常用的創建對象的方法就是以上介紹的3種方式了,接下來說說繼承。
JavaScript的繼承與面嚮對象語言中的繼承不同,JavaScript行數沒有簽名,故只能繼承方法,而不能繼承函數名(例Java中的接口繼承)。JavaScript實現繼承基於原型鏈。
原理:把某個實例對象複製給另一個對象(構造函數)的原型對象
功能:讓一個引用類型繼承另一個引用類型的屬性和方法

//父構造函數
function FatherObject(){
    this.name = "father";
}
FatherObject.prototype.getName = function(){
    return this.name;
}
//子構造函數
function SonObject(){
    this.name = "son";
}
SonObject.prototype.sayName = function(){
    alert(this.name);
}
SonObject.prototype = new FatherObject();
var instance1 = new SonObject();
var instance2 = new SonObject();
alert(instance.sayName());//son
alert(instance.getName());//father

/*原型鏈:instance._proto_ == SonObject.prototype
而SonObject.prototype被賦值爲一個FatherObject對象的實例,SonObject.prototype._proto_== FatherObject.prototype
所以instance對象可以沿着原型鏈訪問以上所有屬性和方法。
其實FatherObject.prototype是Object對象的一個實例,原型鏈最終止於Object對象,這就是爲什麼JavaScript對象都可以訪問toString(),valueOf(),hasOwnProperty()方法的原因*/

原型鏈繼承也有缺陷,上面例子中的instance1和instance2共享FatherObject對象中的name屬性,克服這個缺陷,只需要在子構造函數中調用一下父構造函數即可繼承屬性

function SonObject(){
    FatherObject.call(this, name);
    this.name = "son";
}

原型式繼承:根據一個存在的實例對象創建繼承對象實例

function createObject(o){
    function F(){};
    F.prototype = o;
    return new F();
}
//ECAMScript5中規範爲Object.create()

寄生式繼承:在原型式繼承的基礎上添加新的屬性和方法

function createObject(o){
    var clone = Object.create(o)
    clone.age = 25;
    clone.sayHi = function(){
        alert("hi");
    }
    return clone;
}

尚有不足,後續補全

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章