JavaScript 面向?qū)ο?/h1>

理解對象


EAMCScript中沒有類的概念践樱,所以它與基于類的語言中的對象有所不同庆猫。
ECMAScript-262定義對象為:無序的集合棋蚌,其屬性可以包含基本值雅倒、對象或者函數(shù)璃诀。

屬性類型

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

數(shù)據(jù)屬性

數(shù)據(jù)屬性有4個描述其行為的特性:

  • [[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性蔑匣,能否修改屬性的特性劣欢,能否修改屬性為訪問器屬性。默認值為true裁良。
  • [[Enumerable]]:表示能否通過for-in循環(huán)返回屬性氧秘。默認值為true。
  • [[Writable]]:表示能否修改屬性值趴久。默認值為true丸相。
  • [[Value]]:包含這個屬性的值。默認值為undefined彼棍。

要修改屬性默認的特性灭忠,必須使用ECMAScript5的Object.defineProperty()方法膳算。這個方法接受三個參數(shù):屬性所在的對象,屬性名和一個描述對象弛作。

一旦把屬性定義為不可配置涕蜂,就不能再把它變回可配置了。
在調(diào)用Object.defineProperty()方法時映琳,如果不指定机隙,configurableenumerablewritable特性的默認值都是false萨西。

由于實現(xiàn)的不徹底有鹿,所以不建議在IE8中使用Object.defineProperty()

訪問器屬性

訪問器屬性不包含數(shù)據(jù)值谎脯,它們包含一對gettersetter函數(shù)葱跋。讀取時調(diào)用getter,寫入時調(diào)用setter源梭。
訪問器屬性有4個描述其行為的特性:

  • [[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性娱俺,能否修改屬性的特性,能否修改屬性為數(shù)據(jù)屬性废麻。默認值為true荠卷。
  • [[Enumerable]]:表示能否通過for-in循環(huán)返回屬性。默認值為true烛愧。
  • [[Get]]:在讀取屬性時調(diào)用的函數(shù)僵朗。默認值為undefined。
  • [[Set]]:在寫入屬性時調(diào)用的函數(shù)屑彻。默認值為undefined验庙。

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

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

_year前面的下劃線是一種常用的記號粪薛,用于表示只能通過對象方法訪問的屬性。
支持ECMAScript5的這個方法的瀏覽器有IE9+(IE8只是部分實現(xiàn))搏恤、Firefox4+违寿、Safari5+、Opera12+和Chrome熟空。

定義多個屬性

利用ECMAScript5中的Object.definedProperties()方法來通過描述符一次定義多個屬性藤巢。

讀取屬性的特性

利用ECMAScript5中的Object.getOwnPropertyDescriptor()方法來取得給定屬性的描述符。方法接受兩個參數(shù):屬性所在的對象和屬性名息罗,返回值是一個對象掂咒。

創(chuàng)建對象


工廠模式

這種模式抽象了創(chuàng)建具體對象的過程。考慮到ECMAScript中無法創(chuàng)建類绍刮,開發(fā)人員發(fā)明了一種函數(shù)温圆,用函數(shù)來封裝以特定接口創(chuàng)建對象的細節(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("a", 29, "s");
var person2 = createPerson("b",27 , "d");

構(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("a", 29, "s");
var person2 = new Person("b",27 , "d");

createPerson()Person()的不同之處:

  • 沒有顯示地創(chuàng)建對象
  • 直接將屬性和方法賦予this對象
  • 沒有return語句

按照慣例孩革,構(gòu)造函數(shù)始終以大寫字母開頭岁歉。
調(diào)用構(gòu)造函數(shù)會經(jīng)歷4個步驟:

  1. 創(chuàng)建一個對象
  2. 將構(gòu)造函數(shù)的作用域賦給新對象(因此this指向了這個新的對象)
  3. 執(zhí)行構(gòu)造函數(shù)中的代碼
  4. 返回新對象

對象都有一個constructor屬性。對象的constructor屬性用來標識對象的膝蜈,檢測對象還是用instanceof更好一些锅移。

以這種方式定義的構(gòu)造函數(shù)是定義在Global對象(在瀏覽器中是windows對象)中的。

將構(gòu)造函數(shù)當做函數(shù)
任何函數(shù)饱搏,通過new來調(diào)用就作為一個構(gòu)造函數(shù)非剃,不通過new來調(diào)用就和普通函數(shù)沒什么兩樣。

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

構(gòu)造函數(shù)的問題
使用構(gòu)造函數(shù)的主要問題是每個方法都要在每個實例上重新創(chuàng)建一遍窍帝。
可以將函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部來解決這個問題:

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

上面的問題解決了,可是新的問題又來了:在全局作用域中定義的函數(shù)實際上只能被某個對象調(diào)用诽偷,如果方法很多就要定義很多的全局函數(shù)于是就沒有封裝性可言了坤学。好在,可以通過使用原型模式來解決报慕。

原型模式

創(chuàng)建的每個函數(shù)都有一個prototype屬性深浮,這個屬性是一個指針,指向?qū)ο髮嵗脑蛯ο蟆?/p>

使用原型的好處就是可以讓所有對象實例共享它所包含的屬性和方法眠冈。

function Person(){
}

Person.prototype.name = "a";
Person.prototype.age = 29;
Person.prototype.job = "Software";
Person,prototype.sayName = function(){
    alert(this.name);
};

var person1 = new Person();
person1.sayName(); //a

var person2 = new Person();
person2.sayName(); //a
alert(person1.sayName == person2.sayName); //true

理解原型對象
創(chuàng)建一個新函數(shù)就會根據(jù)一組特定的規(guī)則為函數(shù)創(chuàng)建一個prototype屬性飞苇,這個屬性指向函數(shù)的原型。在默認情況下蜗顽,所有的原型對象都會自動獲得一個constructor屬性布卡,這個屬性指向包含prototype屬性所在的函數(shù)指針。
創(chuàng)建了自定義的構(gòu)造函數(shù)以后雇盖,其原型對象默認只會獲得constructor屬性忿等,其他方法則從Object繼承而來。

通過isPrototypeOf()來判斷對象的原型崔挖。

alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true

ECMAScript5增加了一個新方法贸街,叫Object.getPrototypeOf(),在所有支持的實現(xiàn)中狸相,返回[[Prototype]]的值薛匪。

alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //a

可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值脓鹃。
如果在實例中添加了一個屬性逸尖,且屬性名和原型中的一個屬性同名,那么會在實例中創(chuàng)建該屬性并且屏蔽原型中的同名屬性。不過可以使用delete操作符來刪除實例屬性冷溶,從而重新訪問到原型中的屬性渐白。

使用hasOwnProperty()檢測一個屬性是存在與實例中還是存在于原型中。

原型與in操作符
可以單獨使用和在for-in循環(huán)中使用逞频。
單獨使用in操作符會在通過對象能夠訪問給定屬性時返回true纯衍,無論該屬性存在于實例中還是原型中。

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();
var person2 = new Person();

alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

person1.name = "Greg";
alert(person1.name); //"Greg" ------來自實例
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true

alert(person2.name);  //"Nicholas" ------來自原型
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true

delete person1.name;
alert(person1.name);  //"Nicholas" ------來自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

同時使用hasOwnProperty()in可以確定屬性存在于對象上還是原型上苗胀。

function hasPrototypeProperty(object, name) {
    return !object.hasOwnProperty(name) && (name in object);
}

在使用for-in循環(huán)時襟诸,返回的是所有能夠通過對象訪問的、可枚舉(enumerated)屬性基协,其中即包括存在于實例中的屬性歌亲,也包括存在于原型中的屬性。屏蔽了原型中不可枚舉屬性(即將[[Enumeralbe]]標記的屬性)的實例屬性也會在for-in循環(huán)中返回澜驮,因為根據(jù)規(guī)定陷揪,所有開發(fā)人員定義的屬性都是可枚舉的---只有在IE8及更早的版本例外。
IE早期版本的實現(xiàn)中存在一個bug杂穷,即屏蔽不可枚舉屬性的實例屬性不會出現(xiàn)在for-in循環(huán)中悍缠。

var o = {
    toString : function () {
        return "My Object";
    },
};
for (var prop in o) {
    if (prop == "toString") {
        alert("Found toString"); //在IE中不會顯示
    }
}

要取得對象上所有可枚舉的實例屬性,可以使用ECMAScript5的Object.keys()方法耐量。這個方法接受一個對象作為參數(shù)飞蚓,返回一個包含所有可枚舉屬性的字符串數(shù)組。

function Person() {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
    alert(this.name);
};

var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"

var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"

如果你想要得到所有實例屬性廊蜒,無論它是否可枚舉趴拧,都可以使用Object.getOwnPropertyNames()方法。

var keys = Object.getOwnPropertyNames(Person, prototype);
alert(keys); //"constructor,name,age,job,sayName"

更簡單的原型語法
更常見的做法是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象山叮。

function Person(){
}
Person.prototype = {
    name : "a",
    age : 29,
    job : "Software",
    sayName : function(){
       alert(this.name);
    }
};

以這種形式創(chuàng)建的新對象有一個例外:constructor屬性不在指向Person著榴,而指向Object

如果constructor屬性很重要屁倔,可以將它設(shè)置回適當?shù)闹怠?/p>

function Person(){
}
Person.prototype = {
    constructor : Person,
    name : "a",
    age : 29,
    job : "Software",
    sayName : function(){
       alert(this.name);
    }
};

但是這種方式會導致constructor屬性的[[Enumerable]]特性被設(shè)置為true兄渺。默認情況下,原生的constructor不可枚舉汰现。
使用兼容ECMAScript的引擎可以用下面方法解決:

function Person(){
}
Person.prototype = {
    name : "a",
    age : 29,
    job : "Software",
    sayName : function(){
       alert(this.name);
    }
};
Object.defineProperty(Person.prototype,"constructor",{
    enumerable : false,
    value : Person
}); 

原型的動態(tài)性
對原型對象所做的任何修改都能夠立刻從實例上反應出來挂谍。

var friend = new Person();
Person.prototype.sayHi = function(){
    alert("Hi");
};
friend.sayHi(); //Hi

但是如果重寫整個原型對象,情況就不一樣了瞎饲。

function Person() {
}
var friend = new Person();
Person.prototype = {
    constructor : Person,
    name : "Nicholas",
    age : 29;
    job : "Software";
    sayName : function () {
         alert(this.name);
    }
};
friend.sayName(); //error

原生對象的原型
所有的原生引用類型(Object口叙、Array、String嗅战,等等)都在其構(gòu)造函數(shù)的原型上定義了方法妄田。
通過原生對象的原型俺亮,不僅可以取得所有默認方法的引用,而且也可以定義新的方法疟呐。

不推薦在產(chǎn)品化的程序中修改原生對象的原型脚曾。

原型對象的問題
原型模式也不是沒有缺點。原型模式最大的問題是由其共享的本性所導致的启具。
原型中所有屬性是被很多實例共享的本讥,這種共享對于函數(shù)非常合適。對于那些包含基本值的屬性倒也說得過去鲁冯,通過在實例上添加一個同名屬性拷沸,可以隱藏原型中的對應屬性。然而薯演,對于包含引用類型值得屬性來說毁菱,問題就比較突出了兑牡。

function Person() {
}
Person.prototype = {
    constructor : Person,
    name : "Nicholas",
    age : 29,
    job : "Software",
    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

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

創(chuàng)建自定義類型最常見的方式是組合使用構(gòu)造函數(shù)模式和原型模式有咨。構(gòu)造函數(shù)定義實例屬性携龟,原型模式用于定義方法和共享的屬性。

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}

Person.prototype = {
    constructor : Person,
    syaName : function(){
        alert(this.name);
    }
}

動態(tài)原型模式

動態(tài)原型模式把所有信息都封裝在了構(gòu)造函數(shù)中衡创,而通過在構(gòu)造函數(shù)中初始化原型(僅在必要情況下)帝嗡,又保持了同時使用構(gòu)造函數(shù)和原型的優(yōu)點。

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);
        }
    }
}

寄生構(gòu)造函數(shù)的模式

通常钧汹,在前面幾種模式都不適用的情況下丈探,可以使用寄生(parasitic)構(gòu)造函數(shù)模式录择。這種函數(shù)的基本思想是創(chuàng)建一個函數(shù)拔莱,該函數(shù)的作用僅僅是封裝創(chuàng)建對象的代碼,然后再返回新創(chuàng)建的對象隘竭。

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 friend = new Person("a", 29, "soft");
friend.sayName();

這個模式跟工廠模式很像塘秦。構(gòu)造函數(shù)在不返回值得情況下,默認返回新對象實例动看,而通過在構(gòu)造函數(shù)的末尾添加一個return語句尊剔,可以重寫調(diào)用構(gòu)造函數(shù)時返回的值。
這個模式可以在特殊的情況下用來為對象創(chuàng)建構(gòu)造函數(shù)菱皆。假設(shè)我們想創(chuàng)建一個具有額外方法的特殊數(shù)組须误。由于不能直接修改Array構(gòu)造函數(shù),因此可以使用這個模式仇轻。

function SpecialArray () {
    //創(chuàng)建數(shù)組
    var values = new Array();

    //添加值
    values.push.apply(values, arguments);

    //添加方法
    values.toPipedString = function () {
        return this.join("|");
    };

    //返回數(shù)組
    return values;
}

var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipenString()); //"red|blue|green"

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

穩(wěn)妥對象指的是沒有公共屬性京痢,而且其方法也不引用this的對象。穩(wěn)妥對象最適合在一些安全的環(huán)境中(這些環(huán)境會禁止使用this和new)篷店,或者在防止數(shù)據(jù)被其他應用程序(如Mashup程序)改動時使用祭椰。

function Person (name, age, job) {
    //創(chuàng)建要返回的對象
    var o = new Object();

    //可以在這里定義私有變量和函數(shù)

    //添加方法
    o.sayName = function () {
        alert(name);
    };

    //返回對象
    return o;
}

注意臭家,在以這種模式創(chuàng)建的對象中,除了使用sayName()之外方淤,沒有其他辦法訪問name的值钉赁。

var friend = Person("Nicholas", 29, "Software");
friend.sayName(); //"Nicholas"

繼承


許多的OO語言都支持兩種繼承方式:接口繼承和實現(xiàn)繼承。接口繼承只繼承方法簽名携茂,而實現(xiàn)繼承則繼承實際的方法你踩。由于函數(shù)沒有簽名,在ECMAScript中無法實現(xiàn)接口繼承邑蒋。ECMAScript只支持實現(xiàn)繼承姓蜂,而且其繼承主要是依靠原型鏈來實現(xiàn)。

原型鏈

實現(xiàn)原型鏈有一種基本模式:

function SuperType() {
    this.prototype = true;
}
Super.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

別忘記默認的原型
所有的引用默認都繼承了Object医吊,而這個繼承也是通過原型鏈實現(xiàn)的钱慢。所有函數(shù)的默認原型都是Object的實例,因此默認原型都會包含一個內(nèi)部指針卿堂,指向Object.prototype束莫。

確定原型和實例的關(guān)系
通過兩種方式來確定原型和實例之間的關(guān)系:

  • 使用instanceof操作符檢測實例和原型中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果返回true草描。
alert(instance instanceof Object); //true
  • 使用isPrototypeOf()方法览绿。
alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true

謹慎的定義方法
子類型有時候需要重寫超類型中的某個方法,或者需要添加超類型中不存在的某個方法穗慕。但不管怎么樣饿敲,給原型添加方法的代碼一定要放在替換原型的語句之后。

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;
};

//重寫超類型中的方法
SubType.prototype.getSuperValue = function () {
    return false;
};

var instance = new SubType();
alert(instance.getSuperValue()); //false

這里要注意的是逛绵,必須在用SuperType的實例替換原型以后怀各,再定義這兩個方法。并且通過原型鏈實現(xiàn)繼承時术浪,不能使用對象字面量創(chuàng)建原型方法,因為這樣會重寫原型鏈胰苏。

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;
    },
    someOtherMethod : function () {
        return false;
    }
};

var instance = new SubType();
alert(instance.getSuperValue()); //false

原型鏈的問題
原型鏈雖然很強大法焰,可以用它來實現(xiàn)繼承埃仪,但也存在一些問題琉兜。最主要的問題來自包含引用類型值的原型豌蟋。

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

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

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,black"

原型鏈的第二個問題是:在創(chuàng)建子類型的實例時桑滩,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)幌氮。實際上胁澳,應該說是沒有辦法在不影響所有對象實例的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)韭畸。

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

在解決原型中包含引用類型值所帶來問題的過程中宇智,開發(fā)人員開始使用一種叫做借用構(gòu)造函數(shù)(constructor stealing)的技術(shù)(有時候也叫做偽造對象或經(jīng)典繼承)。即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(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"

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

function SuperType (name) {
    this.name = name;
}

function SubType () {
    //繼承了SuperType,同時還傳遞了參數(shù)
    SuperType.call(this, "Nicholas");

    //實例屬性
    this.age = 29;
}

var instance = new SubType();
alert(instance.name); //"Nicholas"
alert(instance.age); //29

借用構(gòu)造函數(shù)的問題
如果僅僅是借用構(gòu)造函數(shù)拔恰,那么也將無法避免構(gòu)造函數(shù)存在的問題----方法都在構(gòu)造函數(shù)中定義因谎,因此函數(shù)復用就無從談起了。

組合式繼承

組合繼承(combination inheritance)颜懊,有時候也叫做偽經(jīng)典繼承财岔。

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.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

原型式繼承

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

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

var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};
var anotherPerson = objcet(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson.name = objcet(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

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

var person = {
    name : "Nicholas",
    friends : ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson.name = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

寄生式繼承

寄生式繼承創(chuàng)建一個僅用于封裝繼承過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強對象指黎,最后再像真地是它做了所有工作一樣返回對象朋凉。

function createAnother (original) {
    var clone = object(original); //通過調(diào)用函數(shù)創(chuàng)建一個新對象
    clone.sayHi = function () { //以某種方式來增強這個對象
        alert("hi");
    };
    return clone; //返回這個對象
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個濱河市醋安,隨后出現(xiàn)的幾起案子侥啤,更是在濱河造成了極大的恐慌,老刑警劉巖茬故,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盖灸,死亡現(xiàn)場離奇詭異,居然都是意外死亡磺芭,警方通過查閱死者的電腦和手機赁炎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钾腺,“玉大人徙垫,你說我怎么就攤上這事》虐簦” “怎么了姻报?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長间螟。 經(jīng)常有香客問我吴旋,道長,這世上最難降的妖魔是什么厢破? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任荣瑟,我火速辦了婚禮,結(jié)果婚禮上摩泪,老公的妹妹穿的比我還像新娘笆焰。我一直安慰自己,他們只是感情好见坑,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布嚷掠。 她就那樣靜靜地躺著捏检,像睡著了一般。 火紅的嫁衣襯著肌膚如雪不皆。 梳的紋絲不亂的頭發(fā)上未檩,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機與錄音粟焊,去河邊找鬼冤狡。 笑死,一個胖子當著我的面吹牛项棠,可吹牛的內(nèi)容都是我干的悲雳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼香追,長吁一口氣:“原來是場噩夢啊……” “哼合瓢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起透典,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤晴楔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后峭咒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體税弃,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年凑队,在試婚紗的時候發(fā)現(xiàn)自己被綠了则果。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡漩氨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叫惊,到底是詐尸還是另有隱情款青,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布霍狰,位于F島的核電站抡草,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚓耽。R本人自食惡果不足惜渠牲,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一旋炒、第九天 我趴在偏房一處隱蔽的房頂上張望步悠。 院中可真熱鬧,春花似錦瘫镇、人聲如沸鼎兽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谚咬。三九已至鹦付,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間择卦,已是汗流浹背敲长。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秉继,地道東北人祈噪。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像尚辑,于是被迫代替她去往敵國和親辑鲤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容