成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

js面向?qū)ο?

Zhuxy / 3411人閱讀

摘要:如果按照字面意思來理解,那么就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象實(shí)例。

面向?qū)ο?/b>
對(duì)象:是無序?qū)傩缘募?,其屬性可以包含基本值、?duì)象或者函數(shù)。
new運(yùn)算符

創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。
當(dāng)代碼 new Foo(...) 執(zhí)行時(shí),會(huì)發(fā)生以下事情:

一個(gè)繼承自Foo.prototype的新對(duì)象被創(chuàng)建

使用指定的參數(shù)調(diào)用構(gòu)造函數(shù) Foo ,并將 this 綁定到新創(chuàng)建的對(duì)象。

屬性類型

ECMAScript 中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性。

數(shù)據(jù)屬性
數(shù)據(jù)屬性包含一個(gè)數(shù)據(jù)值的位置。在這個(gè)位置可以讀取和寫入值。數(shù)據(jù)屬性有 4 個(gè)描述其行為的特性。

Configurable:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。像前面例子中那樣直接在對(duì)象上定義的屬性,它們的這個(gè)特性默認(rèn)值為 true。

Enumerable:表示能否通過 for-in 循環(huán)返回屬性。像前面例子中那樣直接在對(duì)象上定義的屬性,它們的這個(gè)特性默認(rèn)值為 true。

Writable:表示能否修改屬性的值

Value:包含這個(gè)屬性的數(shù)據(jù)值。讀取屬性值的時(shí)候,從這個(gè)位置讀;寫入屬性值的時(shí)候,把新值保存在這個(gè)位置。這個(gè)特性的默認(rèn)值為 undefined。

要修改屬性默認(rèn)的特性,必須使用 ECMAScript 5 的 Object.defineProperty()方法。這個(gè)方法 接收三個(gè)參數(shù):屬性所在的對(duì)象、屬性的名字和一個(gè)描述符對(duì)象。

var person = {};
Object.defineProperty(person, "name", {
    writable: false,
    value: "Nicholas"
});
alert(person.name); //"Nicholas" 
person.name = "Greg"; 
alert(person.name); //"Nicholas"

把 configurable 設(shè)置為 false,表示不能從對(duì)象中刪除屬性。如果對(duì)這個(gè)屬性調(diào)用 delete,則 在非嚴(yán)格模式下什么也不會(huì)發(fā)生,而在嚴(yán)格模式下會(huì)導(dǎo)致錯(cuò)誤。而且,一旦把屬性定義為不可配置的, 就不能再把它變回可配置了。此時(shí),再調(diào)用 Object.defineProperty()方法修改除 writable 之外 的特性,都會(huì)導(dǎo)致錯(cuò)誤:

var person = {};
Object.defineProperty(person, "name", {
    configurable: false,
    value: "Nicholas"
});
//拋出錯(cuò)誤
Object.defineProperty(person, "name", {
    configurable: true,
    value: "Nicholas"
});

訪問器屬性
訪問器屬性不包含數(shù)據(jù)值;它們包含一對(duì)兒 getter 和 setter 函數(shù)(不過,這兩個(gè)函數(shù)都不是必需的)。 在讀取訪問器屬性時(shí),會(huì)調(diào)用 getter 函數(shù),這個(gè)函數(shù)負(fù)責(zé)返回有效的值;在寫入訪問器屬性時(shí),會(huì)調(diào)用 setter 函數(shù)并傳入新值,這個(gè)函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù)。訪問器屬性有如下 4 個(gè)特性。

Configurable:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特 性,或者能否把屬性修改為數(shù)據(jù)屬性。對(duì)于直接在對(duì)象上定義的屬性,這個(gè)特性的默認(rèn)值為 true。

Enumerable:表示能否通過 for-in 循環(huán)返回屬性。對(duì)于直接在對(duì)象上定義的屬性,這 5 個(gè)特性的默認(rèn)值為 true

Get:在讀取屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為 undefined

Set:在寫入屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為 undefined

訪問器屬性不能直接定義,必須使用 Object.defineProperty()來定義

var book = {
    _year: 2004,
    edition: 1 
};
Object.defineProperty(book, "year", {
    get: function(){
        return this._year;
    },
    set: function(newValue){
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
} }
});
book.year = 2005; 
alert(book.edition); //2

不一定非要同時(shí)指定 getter 和 setter。只指定 getter 意味著屬性是不能寫,嘗試寫入屬性會(huì)被忽略。 在嚴(yán)格模式下,嘗試寫入只指定了 getter 函數(shù)的屬性會(huì)拋出錯(cuò)誤。類似地,只指定 setter 函數(shù)的屬性也不能讀,否則在非嚴(yán)格模式下會(huì)返回 undefined,而在嚴(yán)格模式下會(huì)拋出錯(cuò)誤。

創(chuàng)建對(duì)象 工廠模式

用函數(shù)來封裝以特定接口創(chuàng)建對(duì)象的細(xì)節(jié)

function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o; 
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

函數(shù) createPerson()能夠根據(jù)接受的參數(shù)來構(gòu)建一個(gè)包含所有必要信息的 Person 對(duì)象??梢詿o數(shù)次地調(diào)用這個(gè)函數(shù),而每次它都會(huì)返回一個(gè)包含三個(gè)屬性一個(gè)方法的對(duì)象。

工廠模式雖然解決了創(chuàng)建多個(gè)相似對(duì)象的問題,但卻沒有解決對(duì)象識(shí)別的問題(即怎樣知道一個(gè)對(duì)象的類型)。隨著 JavaScript 的發(fā)展,又一個(gè)新模式出現(xiàn)了。

構(gòu)造函數(shù)模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    }; 
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

好處:

沒有顯式地創(chuàng)建對(duì)象;

直接將屬性和方法賦給了 this 對(duì)象;

沒有 return 語句。

person1 和 person2 分別保存著 Person 的一個(gè)不同的實(shí)例。這兩個(gè)對(duì)象都有一個(gè) constructor(構(gòu)造函數(shù))屬性,該屬性指向 Person,如下所示

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

對(duì)象的 constructor 屬性最初是用來標(biāo)識(shí)對(duì)象類型的。但是,提到檢測(cè)對(duì)象類型,還是 instan- ceof 操作符要更可靠一些。我們?cè)谶@個(gè)例子中創(chuàng)建的所有對(duì)象既是 Object 的實(shí)例,同時(shí)也是 Person 的實(shí)例,這一點(diǎn)通過 instanceof 操作符可以得到驗(yàn)證。

alert(person1 instanceof Object);  //true
alert(person1 instanceof Person);  //true
alert(person2 instanceof Object);  //true
alert(person2 instanceof Person);  //true

將構(gòu)造函數(shù)當(dāng)作函數(shù)
構(gòu)造函數(shù)與其他函數(shù)的唯一區(qū)別,就在于調(diào)用它們的方式不同。不過,構(gòu)造函數(shù)畢竟也是函數(shù),不 存在定義構(gòu)造函數(shù)的特殊語法。任何函數(shù),只要通過 new 操作符來調(diào)用,那它就可以作為構(gòu)造函數(shù);而 任何函數(shù),如果不通過 new 操作符來調(diào)用,那它跟普通函數(shù)也不會(huì)有什么兩樣。

// 當(dāng)作構(gòu)造函數(shù)使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作為普通函數(shù)調(diào)用
Person("Greg", 27, "Doctor"); // 添加到window 
window.sayName(); //"Greg"
// 在另一個(gè)對(duì)象的作用域中調(diào)用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse"); 
o.sayName(); //"Kristen"

這個(gè)例子中的前兩行代碼展示了構(gòu)造函數(shù)的典型用法,即使用 new 操作符來創(chuàng)建一個(gè)新對(duì)象。

接下來的兩行代碼展示了不使用new 操作符調(diào)用 Person()會(huì)出現(xiàn)什么結(jié)果:屬性和方法都被添加給 window 對(duì)象了。當(dāng)在全局作用域中調(diào)用一個(gè)函數(shù)時(shí),this對(duì)象總是指向Global 對(duì)象(在瀏覽器中就是window對(duì)象)。因此,在調(diào)用完函數(shù)之后,可以通過 window 對(duì)象來調(diào)用 sayName()方法,并且還返回了"Greg"。

最后,也可以使用call()(或者apply())在某個(gè)特殊對(duì)象的作用域中調(diào)用Person()函數(shù)。這里是在對(duì)象o的作用域中調(diào)用的,因此調(diào)用后o就擁有了所有屬性和sayName()方法。

構(gòu)造函數(shù)的問題
使用構(gòu)造函數(shù)的主要問題,就是每個(gè)方法都要在每個(gè) 實(shí)例上重新創(chuàng)建一遍。在前面的例子中,person1 和 person2 都有一個(gè)名為 sayName()的方法,但那 兩個(gè)方法不是同一個(gè) Function 的實(shí)例。
以這種方式創(chuàng)建函數(shù),會(huì)導(dǎo)致不同的作用域鏈和標(biāo)識(shí)符解析,但創(chuàng)建 Function 新實(shí)例的機(jī)制仍然是相同的。因此,不同實(shí)例上的同名函數(shù)是不相等的,以下代碼可以證明這一點(diǎn)

alert(person1.sayName == person2.sayName);  //false
原型模式

我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè) prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象, 而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。如果按照字面意思來理解,那 么 prototype 就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。使用原型對(duì)象的好處是可以 讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。換句話說,不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是 可以將這些信息直接添加到原型對(duì)象中,如下面的例子所示。

function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
    alert(this.name);
};
var person1 = new Person();
person1.sayName();   //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName);  //true

理解原型對(duì)象
無論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè) constructor (構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向 prototype 屬性所在函數(shù)的指針。就拿前面的例子來說, Person.prototype.constructor 指向 Person。而通過這個(gè)構(gòu)造函數(shù),我們還可繼續(xù)為原型對(duì)象添加其他屬性和方法。

創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得 constructor 屬性;至于其他方法,則都是從 Object 繼承而來的。當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部 屬性),指向構(gòu)造函數(shù)的原型對(duì)象。ECMA-262 第 5 版中管這個(gè)指針叫[[Prototype]]。雖然在腳本中 沒有標(biāo)準(zhǔn)的方式訪問[[Prototype]],但 Firefox、Safari 和 Chrome 在每個(gè)對(duì)象上都支持一個(gè)屬性 __proto__;而在其他實(shí)現(xiàn)中,這個(gè)屬性對(duì)腳本則是完全不可見的。不過,要明確的真正重要的一點(diǎn)就 是,這個(gè)連接存在于實(shí)例與構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在于實(shí)例與構(gòu)造函數(shù)之間。

使用 hasOwnProperty()方法可以檢測(cè)一個(gè)屬性是存在于實(shí)例中,還是存在于原型中。這個(gè)方法(不 要忘了它是從 Object 繼承來的)只在給定屬性存在于對(duì)象實(shí)例中時(shí),才會(huì)返回 true。

有兩種方式使用 in 操作符:多帶帶使用和在 for-in 循環(huán)中使用。在多帶帶使用時(shí),in 操作符會(huì)在通 過對(duì)象能夠訪問給定屬性時(shí)返回 true,無論該屬性存在于實(shí)例中還是原型中。

由于 in 操作符只要通過對(duì)象能夠訪問到屬性就返回 true,hasOwnProperty()只在屬性存在于 實(shí)例中時(shí)才返回 true,因此只要 in 操作符返回 true 而 hasOwnProperty()返回 false,就可以確 定屬性是原型中的屬性。

原型對(duì)象的問題
所有實(shí)例在默認(rèn)情況下都將取得相同的屬性值

function Person() {}
Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
        alert(this.name);
    } 
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Court,Van"
alert(person2.friends);    //"Shelby,Court,Van"
alert(person1.friends === person2.friends);  //true

Person.prototype對(duì)象有一個(gè)名為friends的屬性,該屬性包含一個(gè)字符串?dāng)?shù)組。然后, 創(chuàng)建了 Person 的兩個(gè)實(shí)例。接著,修改了 person1.friends 引用的數(shù)組,向數(shù)組中添加了一個(gè)字符 串。由于 friends 數(shù)組存在于 Person.prototype 而非 person1 中,所以剛剛提到的修改也會(huì)通過 person2.friends(與 person1.friends 指向同一個(gè)數(shù)組)反映出來。

組合使用構(gòu)造函數(shù)模式和原型模式

構(gòu)造函數(shù)模式用于定義實(shí)例屬性,而原型模式用于定義方法和共享的屬性。結(jié)果,每個(gè)實(shí)例都會(huì)有自己的一份實(shí)例屬性的副本,但同時(shí)又共享著對(duì)方法的引用,最大限度地節(jié)省了內(nèi)存。另外,這種混成模式還支持向構(gòu)造函數(shù)傳遞參數(shù);可謂是集兩種模式之長(zhǎng)

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}
Person.prototype = {
    constructor : Person,
    sayName : function(){
        alert(this.name);
    }
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends);    //"Shelby,Count,Van"
alert(person2.friends);    //"Shelby,Count"
alert(person1.friends === person2.friends);   //false
alert(person1.sayName === person2.sayName);   //true
動(dòng)態(tài)原型模式

通過檢查某個(gè)應(yīng)該存在的方法是否有效,來決定是否需要初始化原型。

function Person(name, age, job){
    //屬性
    this.name = name; 
    this.age = age; 
    this.job = job;
    //方法
    if (typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        }; 
    }
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();
寄生構(gòu)造函數(shù)模式

這種模式的基本思想是創(chuàng)建一個(gè)函數(shù),該函數(shù)的作用僅僅是封裝創(chuàng)建對(duì)象的代碼,然后再返回新創(chuàng)建的對(duì)象

function Person(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o; 
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();  //"Nicholas"

在這個(gè)例子中,Person 函數(shù)創(chuàng)建了一個(gè)新對(duì)象,并以相應(yīng)的屬性和方法初始化該對(duì)象,然后又返 回了這個(gè)對(duì)象。除了使用 new 操作符并把使用的包裝函數(shù)叫做構(gòu)造函數(shù)之外,這個(gè)模式跟工廠模式其實(shí) 是一模一樣的。構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象實(shí)例。而通過在構(gòu)造函數(shù)的末尾添加一個(gè) return 語句,可以重寫調(diào)用構(gòu)造函數(shù)時(shí)返回的值。
這個(gè)模式可以在特殊的情況下用來為對(duì)象創(chuàng)建構(gòu)造函數(shù)。假設(shè)我們想創(chuàng)建一個(gè)具有額外方法的特殊數(shù)組。由于不能直接修改 Array 構(gòu)造函數(shù),因此可以使用這個(gè)模式。

function SpecialArray(){
    //創(chuàng)建數(shù)組
    var values = new Array();
    values.push.apply(values, arguments);
    //添加方法
    values.toPipedString = function(){
        return this.join("|");
    };
    //返回?cái)?shù)組
    return values;
}
var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"

需要說明:首先,返回的對(duì)象與構(gòu)造函數(shù)或者與構(gòu)造函數(shù)的原型屬性之間沒有關(guān)系;也就是說,構(gòu)造函數(shù)返回的對(duì)象與在構(gòu)造函數(shù)外部創(chuàng)建的對(duì)象沒有什么不同。為此,不能依賴 instanceof 操作符來確定對(duì)象類型。由于存在上述問題,我們建議在可以使用其他模式的情況下,不要使用這種模式。

穩(wěn)妥構(gòu)造函數(shù)模式

所謂穩(wěn)妥對(duì)象,指的是沒有公共屬性,而且其方法也不引用 this 的對(duì)象。穩(wěn)妥對(duì)象最適合在 一些安全的環(huán)境中(這些環(huán)境中會(huì)禁止使用 this 和 new),或者在防止數(shù)據(jù)被其他應(yīng)用程序(如 Mashup 程序)改動(dòng)時(shí)使用。穩(wěn)妥構(gòu)造函數(shù)遵循與寄生構(gòu)造函數(shù)類似的模式,但有兩點(diǎn)不同:一是新創(chuàng)建對(duì)象的 實(shí)例方法不引用 this;二是不使用 new 操作符調(diào)用構(gòu)造函數(shù)。按照穩(wěn)妥構(gòu)造函數(shù)的要求,可以將前面 的 Person 構(gòu)造函數(shù)重寫如下。

function Person(name, age, job){
    //創(chuàng)建要返回的對(duì)象
    var o = new Object();
    //可以在這里定義私有變量和函數(shù)
    
    //添加方法
    o.sayName = function(){
        alert(name);
    };
    //返回對(duì)象
    return o; 
}

在以這種模式創(chuàng)建的對(duì)象中,除了使用 sayName()方法之外,沒有其他辦法訪問 name 的值。 可以像下面使用穩(wěn)妥的 Person 構(gòu)造函數(shù)。

即使有其他代碼會(huì)給這個(gè)對(duì)象添加方法或數(shù)據(jù)成員,但也不可能有別的辦法訪問傳 入到構(gòu)造函數(shù)中的原始數(shù)據(jù)。穩(wěn)妥構(gòu)造函數(shù)模式提供的這種安全性,使得它非常適合在某些安全執(zhí)行環(huán) 境——例如,ADsafe(www.adsafe.org)和 Caja(http://code.google.com/p/goog... )提供的環(huán)境—— 下使用。

繼承 原型鏈
構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}
function SubType(){
    this.subproperty = false;
}

//繼承了 SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function (){
    return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());    //true

問題:包含引用類型值的原型屬性會(huì)被所有實(shí)例共享;在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)

借用構(gòu)造函數(shù)

在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù);函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象, 因此通過使用 apply()和 call()方法也可以在(將來)新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù),如下所示

function SuperType() {
    this.colors = ["red", "blue", "green"]
}

function SubType(){
    //繼承了 SuperType
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"

代碼中“借調(diào)”了超類型的構(gòu)造函數(shù)。通過使用 call()方法(或 apply()方法 也可以),我們實(shí)際上是在(未來將要)新創(chuàng)建的 SubType 實(shí)例的環(huán)境下調(diào)用了 SuperType 構(gòu)造函數(shù)。 這樣一來,就會(huì)在新 SubType 對(duì)象上執(zhí)行 SuperType()函數(shù)中定義的所有對(duì)象初始化代碼。結(jié)果, SubType 的每個(gè)實(shí)例就都會(huì)具有自己的 colors 屬性的副本了。

優(yōu)勢(shì):相對(duì)于原型鏈而言,借用構(gòu)造函數(shù)有一個(gè)很大的優(yōu)勢(shì),即可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)。

問題:如果僅僅是借用構(gòu)造函數(shù),那么無法避免構(gòu)造函數(shù)模式存在的問題——方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無從談起了。而且,在超類型的原型中定義的方法,對(duì)子類型而言也是不可見的,結(jié) 果所有類型都只能使用構(gòu)造函數(shù)模式。考慮到這些問題,借用構(gòu)造函數(shù)的技術(shù)也是很少多帶帶使用的。

組合繼承

思路:使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
}
function SubType(name, age){
    //繼承屬性 
    SuperType.call(this, name);
    this.age = age;
}

//繼承方法
SubType.prototype = new SuperType(); 
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
    alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);   //"red,blue,green,black"
instance1.sayName();       //"Nicholas";
instance1.sayAge();        //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors);    //"red,blue,green"
instance2.sayName();        //"Greg";
instance2.sayAge();         //27
原型式繼承

借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型。

function object(o){
    function F(){}
    F.prototype = o
    return new F()

在object()函數(shù)內(nèi)部,先創(chuàng)建了一個(gè)臨時(shí)性的構(gòu)造函數(shù),然后將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回了這個(gè)臨時(shí)類型的一個(gè)新實(shí)例。從本質(zhì)上講,object()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制。e.g.

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
    anotherPerson.name = "Greg";
    anotherPerson.friends.push("Rob");
    
var yetAnotherPerson = object(person);
    yetAnotherPerson.name = "Linda";
    yetAnotherPerson.friends.push("Barbie");
// 這相當(dāng)于創(chuàng)建了 person 對(duì)象的兩個(gè)副本。
  
alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"

ECMAScript 5 通過新增 Object.create()方法規(guī)范化了原型式繼承。這個(gè)方法接收兩個(gè)參數(shù):一 個(gè)用作新對(duì)象原型的對(duì)象和(可選的)一個(gè)為新對(duì)象定義額外屬性的對(duì)象。在傳入一個(gè)參數(shù)的情況下, Object.create()與 object()方法的行為相同。

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
    anotherPerson.name = "Greg";
    anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
    yetAnotherPerson.name = "Linda";
    yetAnotherPerson.friends.push("Barbie");
    
alert(person.friends);    //"Shelby,Court,Van,Rob,Barbie"
寄生式繼承

寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后再像真地是它做了所有工作一樣返回對(duì)象。以下代碼示范了寄生式繼承模式

function createAnother(original){
    var clone = object(original)    //通過調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
    clone.sayHi = function() {      //以某種方式來增強(qiáng)這個(gè)對(duì)象
        alert("hi")
    }
    return clone;                   //返回這個(gè)對(duì)象
}
寄生組合式繼承

組合繼承最大的 問題就是無論什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候,另一次是 在子類型構(gòu)造函數(shù)內(nèi)部。沒錯(cuò),子類型最終會(huì)包含超類型對(duì)象的全部實(shí)例屬性,但我們不得不在調(diào)用子 類型構(gòu)造函數(shù)時(shí)重寫這些屬性。
寄生組合式繼承的基本模式如下所示。

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype); //創(chuàng)建超類型原型的一個(gè)副本
    prototype.constructor = subType; //為創(chuàng)建的副本添加 constructor 屬性,從而彌補(bǔ)因重寫原型而失去的默認(rèn)的 constructor 屬性
    subType.prototype = prototype; //將新創(chuàng)建的對(duì)象(即副本)賦值給子類型的原型
}
function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
    alert(this.age);
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94626.html

相關(guān)文章

  • JS面向對(duì)象之一 【概述】

    摘要:更形象的我們還可以將面向?qū)ο罄斫鉃橐环N宗教信仰。這就導(dǎo)致面向?qū)ο蠼痰某绦騿T們?cè)趯憰r(shí)就很難受。所以為了滿足信仰面向?qū)ο蠼痰男枨笸ㄟ^構(gòu)造函數(shù)的形式模擬了偽類。這個(gè)套路的核心就是類那么里沒有類所以其實(shí)是通過構(gòu)造函數(shù)來模擬的偽類。 JS面向?qū)ο笾?【概述】 在學(xué)習(xí)JS的面向?qū)ο笾?我們應(yīng)該先自問這樣幾個(gè)問題: 面向?qū)ο笫鞘裁匆馑? 學(xué)習(xí)面向?qū)ο蟮暮诵氖鞘裁? 為什么要學(xué)習(xí)面向?qū)ο?(它的...

    JohnLui 評(píng)論0 收藏0
  • 面向對(duì)象的 JavaScript

    摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長(zhǎng)期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽?,從?duì)語言感悟的角度闡述為什...

    novo 評(píng)論0 收藏0
  • 體驗(yàn)javascript之美6:如果你覺得什么都會(huì)了或者不知道js學(xué)什么了看這里-面向對(duì)象編程

    摘要:面向過程函數(shù)式編程面向?qū)ο缶幊痰诙€(gè)并不是大家理解的那樣,我們先說舉個(gè)現(xiàn)實(shí)例子就明白了。多說一句函數(shù)是編程是非常強(qiáng)大也是我最喜歡的,以后再說,我們先說面向?qū)ο缶幊獭? 概述 當(dāng)大家已經(jīng)把js的語言基礎(chǔ)理解了,然后能夠?qū)懗鲆恍┖?jiǎn)單的例子了,這個(gè)時(shí)候基本上達(dá)到了一年工作經(jīng)驗(yàn)的水平,而自己能夠獨(dú)立的寫一些小功能,完成一些小效果,或者臨摹修改一些比較復(fù)雜的插件的時(shí)候差不多就是兩年工作經(jīng)驗(yàn)的水平,...

    changfeng1050 評(píng)論0 收藏0
  • JS對(duì)象(1)重新認(rèn)識(shí)面向對(duì)象

    摘要:對(duì)象重新認(rèn)識(shí)面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對(duì)象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過構(gòu)造器創(chuàng)建對(duì)象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對(duì)象該函數(shù)對(duì)象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對(duì)象(1)重新認(rèn)識(shí)面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對(duì)象是...

    superw 評(píng)論0 收藏0
  • JS面向對(duì)象一:MVC的面向對(duì)象封裝

    摘要:自己的理解的第一個(gè)參數(shù)就是的值如果沒用默認(rèn)是那個(gè)調(diào)用函數(shù)的當(dāng)前的對(duì)象在全局作用域中就是被隱藏的所以不寫且在全局作用于調(diào)用函數(shù)的時(shí)候就是可以使用或者自己指定的指向 JS面向?qū)ο笠?MVC的面向?qū)ο蠓庋b MDNjavascript面向?qū)ο?面向?qū)ο?Object-Oriented) showImg(https://segmentfault.com/img/remote/1460000016...

    Scliang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<