成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JavaScript面向?qū)ο蟮某绦蛟O(shè)計(jì)

GitCafe / 2223人閱讀

摘要:前言說(shuō)到面向?qū)ο?,可能第一想到的是或者這樣的語(yǔ)言。默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)構(gòu)造函數(shù)屬性會(huì)執(zhí)行屬性所在函數(shù)。相對(duì)于原型鏈而言,借用構(gòu)造函數(shù)有一個(gè)很大的優(yōu)勢(shì),即

前言

說(shuō)到面向?qū)ο?,可能第一想到的是C++或者Java這樣的語(yǔ)言。這些語(yǔ)言有都一個(gè)標(biāo)志,那就是引入了類的概念。我們可以通過(guò)類創(chuàng)建任意數(shù)量的具有相同屬性和方法的對(duì)象。ECMAScript(JavaScript分為ECMAScript、DOM和BOM)中沒(méi)有類的概念,所以它的對(duì)象相比較基于類的語(yǔ)言還是有所不同的。

說(shuō)說(shuō)對(duì)象的屬性
 var person={
        name:"張三",
        age:23,
        sex:"男",
        sayName:function () {
            alert(this.name);
        }
    }

上面我們用了對(duì)象字面量的方式建了一個(gè)非常簡(jiǎn)單的person對(duì)象,他擁有name、age、sex、sayName這些屬性,而這些屬性在創(chuàng)建時(shí)都帶有一些特征值,JavaScript通過(guò)這些特征值就可以定義這些屬性的行為。在ECMAScript中,屬性分為兩種:數(shù)據(jù)屬性和訪問(wèn)器屬性。下面我們一一學(xué)習(xí)下。

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

數(shù)據(jù)屬性有四個(gè)特征值,分別為如下四個(gè):

configurable
表示能否delete刪除屬性,能否修改屬性的特性,默認(rèn)值是false

enumerable
表示能否通過(guò)for-in循環(huán)返回屬性,默認(rèn)值是false

writable
表示能否修改屬性的值,默認(rèn)值是false

value
表示該屬性的值,我們讀取和修改都是在這個(gè)位置,默認(rèn)值是undefined

接下來(lái)我們一一理解這四個(gè)特征值。要修改屬性默認(rèn)的特性,必須使用ECMAScript 5的Object.defineProperty()方法

configurable
1.delete無(wú)效
    var person={};
    Object.defineProperty(person,"name",{
        configurable:false,
        value:"張三"
    });
    console.log(person.name);//張三
    delete person.name;
    console.log(person.name);//張三
2.不能修改屬性的特性
    var person={};
    Object.defineProperty(person,"name",{
        configurable:true,
        value:"張三"
    });
    Object.defineProperty(person,"name",{
        value:"李四"
    });
    console.log(person.name);//李四
    var person={};
    Object.defineProperty(person,"name",{
        configurable:false,
        value:"張三"
    });
    Object.defineProperty(person,"name",{
        value:"李四"
    });
    console.log(person.name);
    
    //控制臺(tái)報(bào)錯(cuò) Uncaught TypeError: Cannot redefine property: name
enumerable
    var person={};
    Object.defineProperty(person,"name",{
        enumerable:true,
        value:"張三"
    });
    Object.defineProperty(person,"age",{
        value:"23"
    });
    Object.defineProperty(person,"sayName",{
        enumerable:true,
        value:function () {
            alert(this.name);
        }
    });
    for( var prop in person){
        console.log(prop);
    }
    //控制臺(tái)輸出 name和sayName
writable
    var person={};
    Object.defineProperty(person,"name",{
        writable:false,
        value:"張三"
    });
    console.log(person.name);//張三
    person.name="李四";
    console.log(person.name);//張三
value
    var person={};
    Object.defineProperty(person,"name",{
        writable:true,
        value:"張三"
    });
    console.log(person.name);//張三
    person.name="李四";
    console.log(person.name);//李四
訪問(wèn)器屬性

訪問(wèn)器屬性有四個(gè)特征值,分別為如下四個(gè):

configurable
表示能否delete刪除屬性,能否修改屬性的特性,默認(rèn)值是false

enumerable
表示能否通過(guò)for-in循環(huán)返回屬性,默認(rèn)值是false

get
在讀取屬性調(diào)用的函數(shù),默認(rèn)值是undefined

set
在設(shè)置屬性調(diào)用的函數(shù),默認(rèn)值是undefined

下面我們一一了解一下訪問(wèn)器屬性的特征值,其中configurable和enumerable與上面數(shù)據(jù)類型一樣,這里我們就不多做介紹,主要我們說(shuō)一下get和set。

 var person={
        name:"張三",
        age:32
    };
    Object.defineProperty(person,"sayAge",{
        get:function () {
            return this.name+":"+this.age+"歲";
        },
        set:function (newAge) {
            console.log("想要重返"+newAge+"歲?不存在的!");
        }
    });
    console.log(person.sayAge);//張三:32歲
    person.sayAge=18;//想要重返18歲?不存在的!
    console.log(person.sayAge);//張三:32歲

get和set并非需要同時(shí)都要指定。如果只指定get,那么這個(gè)屬性就是不可寫的;如果只指定set,那么這個(gè)屬性就是不可讀的。

 var person1={
        name:"張三",
        age:32
    };
    Object.defineProperty(person1,"sayAge",{
        get:function () {
            return this.name+":"+this.age+"歲";
        }
    });
    console.log(person1.sayAge);//張三:32歲
    person1.sayAge=18;
    console.log(person1.sayAge);//張三:32歲

    var person2={
        name:"李四",
        age:46
    };
    Object.defineProperty(person2,"sayAge",{
        set:function () {
            console.log("想要重返18歲?不存在的!");
        }
    });
    console.log(person2.sayAge);//undefined
    person2.sayAge=18;//想要重返18歲?不存在的!
    console.log(person2.sayAge);//undefined
定義多個(gè)屬性

這個(gè)里我們就要說(shuō)一個(gè)Object.defineProperties()方法,具體用下看如下示例:

    var person = {};
    Object.defineProperties(person, {
        name: {
            writable: true,
            value: "張三"
        },
        age: {
            enumerable: true,
            value: 23,
        },
        sayName: {
            get: function () {
                return this.name;
            },
            set: function (newName) {
                console.log("名字修改完成");
                this.name=newName+"(修改)";
            }
        }
    });
讀取屬性的特性

這里我們可以正好驗(yàn)證我們前面所有默認(rèn)值。

    var person={};
    Object.defineProperty(person,"name",{
        value:"張三"
    });
    var descriptor=Object.getOwnPropertyDescriptor(person,"name");
    console.log("configurable:"+descriptor.configurable);
    //configurable:false
    console.log("enumerable:"+descriptor.enumerable);
    //enumerable:false
    console.log("writable:"+descriptor.writable);
    //writable:false
    console.log("value:"+descriptor.value);
    //張三
創(chuàng)建對(duì)象 字面量模式
    var person={};
    person.name="張三";
    person.age=22;
    person.sex="男";
    person.sayName=function () {
        alert(this.name);
    }

優(yōu)點(diǎn):創(chuàng)建單個(gè)對(duì)象簡(jiǎn)單方便
缺點(diǎn):創(chuàng)建多個(gè)相似對(duì)象會(huì)產(chǎn)生大量代碼

工廠模式
    function createPerson(name, age, sex) {
        var person = new Object();
        person.name = name;
        person.age = age;
        person.sex = sex;
        person.sayName = function () {
            alert(this.name);
        };
        return person;
    }
    var person=createPerson("張三",22,"男");

優(yōu)點(diǎn):可以快速創(chuàng)建多個(gè)相似對(duì)象
缺點(diǎn):無(wú)法進(jìn)行對(duì)象的識(shí)別

構(gòu)造函數(shù)模式
     function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.sayName = function () {
            alert(this.name);
        };
    }
    var person=new Person("張三",22,"男");

以構(gòu)造函數(shù)的方式創(chuàng)建對(duì)象要經(jīng)歷下面四個(gè)步驟:

創(chuàng)建一個(gè)新對(duì)象

將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this指向這個(gè)新對(duì)象)

執(zhí)行構(gòu)造函數(shù)中的代碼,為這個(gè)新對(duì)象添加屬性

返回新對(duì)象

這里person有一個(gè)constructor(構(gòu)造函數(shù))屬性指向Person,我們可以驗(yàn)證一下。

    alert(person.constructor===Person);//true

鑒于這個(gè)特性我們可以用constructor來(lái)驗(yàn)證對(duì)象的類型。除了這個(gè),我們還可以利用instanceof。

    alert(person instanceof Person);//true

雖然我們使用構(gòu)造函數(shù)模式可以進(jìn)行對(duì)象的識(shí)別,但是構(gòu)造函數(shù)模式卻有一個(gè)缺點(diǎn),就是每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍。下面我們舉個(gè)例子說(shuō)明一下。

    function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.sayName = function () {
            alert(this.name);
        };
    }
    var person1=new Person("張三",22,"男");
    var person2=new Person("李四",25,"男");
    alert(person1.sayName===person2.sayName);//false

從上面的例子我們看出來(lái),person1和person2的sayName函數(shù)并非共用同一個(gè)。

優(yōu)點(diǎn):可以進(jìn)行對(duì)象的識(shí)別
缺點(diǎn):構(gòu)造函數(shù)里面的函數(shù)在實(shí)例化的時(shí)候都需要每次都創(chuàng)建一遍,導(dǎo)致不同作用域鏈和標(biāo)識(shí)符解析。

原型模式
   function Person() {

   }
   Person.prototype.name="張三";
   Person.prototype.age=22;
   Person.prototype.sex="男";
   Person.prototype.sayName=function () {
       alert(this.name);
   };
   var person=new Person();

任何時(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ù))屬性會(huì)執(zhí)行prototype屬性所在函數(shù)。以上面這個(gè)例子為例,即:

Person.prototype.constructor===Person//true

另外我們的實(shí)例對(duì)象都會(huì)有一個(gè)__proto__屬性指向構(gòu)造函數(shù)的原型對(duì)象。即:

person.__proto__===Person.prototype //true

接下來(lái)我們要說(shuō)的一點(diǎn)是我們可以通過(guò)對(duì)象實(shí)例訪問(wèn)保存在原型中的值,但是不能通過(guò)對(duì)象實(shí)例重寫原型中的值。下面我們看個(gè)例子:

   function Person() {

   }
   Person.prototype.name="張三";
   Person.prototype.age=22;
   Person.prototype.sex="男";
   Person.prototype.sayName=function () {
       alert(this.name);
   };
   var person1=new Person();
   var person2=new Person();
   person1.name="李四";
   alert(person1.name);//李四
   alert(person2.name);//張三

從上面的例子我們可以看出,我們修改了person1的name屬性實(shí)際是實(shí)例對(duì)象person1中的屬性,而不是Person.prototype原型對(duì)象。如果我們想要person1.name指向Person.prototype.name則需要?jiǎng)h除實(shí)例對(duì)象person1中name屬性,如下所示:

   delete person1.name;
   alert(person1.name);//張三

說(shuō)到這里我們遇到一個(gè)一個(gè)問(wèn)題,就是如何判斷一個(gè)屬性在原型上還是在實(shí)例對(duì)象上?這個(gè)是有方法可以做到的,那就是hasOwnProperty()方法,接著上面的代碼,我們可以用這個(gè)hasOwnProperty()方法去驗(yàn)證一下。

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

上面我們刪除實(shí)例對(duì)象person1中name屬性之后,name應(yīng)該不屬于實(shí)例對(duì)象person1的屬性,所以hasOwnProperty()返回false.
如果只是想知道person1能否訪問(wèn)name屬性,不論在實(shí)例對(duì)象上還是原型上的話,我們可以用in操作符。如下所示:

   alert("name" in person1);//true

相對(duì)上面的原型語(yǔ)法,我們有一個(gè)相對(duì)簡(jiǎn)單的原型語(yǔ)法。

    function Person() {

    }
    Person.prototype = {
        constructor:Person,
        name: "張三",
        age: 22,
        sex:"男",
        sayName: function () {
            alert(this.name);
        }
    };

這里注意的是,需要重新設(shè)置constructor為Person,否則constructor指向Object而不是Person。但是這樣有一個(gè)缺點(diǎn),就是constructor的enumerable特性被設(shè)為true。導(dǎo)致constructor屬性由原本不可枚舉變成可枚舉。如果想解決這個(gè)問(wèn)題可以嘗試這種寫法:

    function Person() {

    }
    Person.prototype = {
        name: "張三",
        age: 22,
        sex:"男",
        sayName: function () {
            alert(this.name);
        }
    };
    Object.defineProperty(Person.prototype,"constructor",{
        enumerable:false,
        value:Person
    });

說(shuō)完這個(gè)之后,我們來(lái)說(shuō)一下原型的動(dòng)態(tài)性。由于在原型中查找值的過(guò)程是一次搜索,因此我們對(duì)原型對(duì)象所做的任何修改都能夠立即從實(shí)例上反映出來(lái)。我們看一下下面的例子:

   function Person() {

   }
   var person=new Person();
   person.name="張三";
   person.sayName=function () {
     alert(this.name);
   };
   person.sayName();//張三

但是在重寫整個(gè)原型對(duì)象的時(shí)候情況就不一樣了,我們看一下下面這個(gè)例子:

    function Person() {

    }
    var person = new Person();
    Person.prototype = {
        constructor:Person,
        name: "張三",
        age: 22,
        sayName: function () {
            alert(this.name);
        }
    };
    person.sayName();
    //Uncaught TypeError: person.sayName is not a function

重寫原型對(duì)象會(huì)切斷現(xiàn)有原型與任何之前已經(jīng)存在的對(duì)象實(shí)例之間的聯(lián)系,引用的仍然是最初的原型,上面的例子由于最初的原型的沒(méi)有sayName()方法,所以會(huì)報(bào)錯(cuò)。

優(yōu)點(diǎn):可以進(jìn)行對(duì)象的識(shí)別,以及實(shí)例對(duì)象的函數(shù)不會(huì)被重復(fù)創(chuàng)建,從而不會(huì)導(dǎo)致不同的作用域鏈。
缺點(diǎn):省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),所有實(shí)例在默認(rèn)情況都取相同的值。

組合使用構(gòu)造函數(shù)模式和原型模式
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype = {
        constructor:Person,
        sayName: function () {
            alert(this.name);
        }
    };
    var person1 = new Person("張三", 22);
    var person2 = new Person("李四", 23);
    alert(person1.sayName===person2.sayName);//true

優(yōu)點(diǎn):結(jié)合構(gòu)造函數(shù)模式和原型模式的優(yōu)點(diǎn),是目前使用最廣泛、認(rèn)同度最高的一種創(chuàng)建自定義類型的方法。

動(dòng)態(tài)原型模式
    function Person(name,age,sex) {
        this.name=name;
        this.age=age;
        this.sex=sex;
        if(typeof this.sayName!="function"){
            Person.prototype.sayName=function () {
              alert(this.name);
            };
        }
    }
    var person=new Person("張三",22,"男");
    person.sayName();//張三

上面代碼中if語(yǔ)句只有在初次調(diào)用構(gòu)造函數(shù)時(shí)才會(huì)執(zhí)行。此后,原型已經(jīng)初始化,不需要再做什么修改了。
優(yōu)點(diǎn):保留了構(gòu)造函數(shù)模式和原型模式的優(yōu)點(diǎn),又將所有信息封裝信息封裝在了構(gòu)造函數(shù)中。

寄生構(gòu)造函數(shù)模式(了解即可)
    function Person(name,age,sex) {
        var object=new Object();
        object.name=name;
        object.age=age;
        object.sex=sex;
        object.sayName=function () {
            alert(this.name);
        };
        return object;
    }
    var person=new Person("張三",22,"男");
    person.sayName();//張三

由于我們可以重寫調(diào)用構(gòu)造函數(shù)時(shí)的返回值,所以我們可以在特殊情況下為對(duì)象創(chuàng)建構(gòu)造函數(shù)。例如我們想創(chuàng)建一個(gè)具有特殊方法的數(shù)組,由于我們不能修改Array構(gòu)造函數(shù),因此可以使用這種方式。

    function SpecialArray() {
        var values=new Array();
        values.push.apply(values,arguments);
        values.toPipedString=function () {
            return this.join("|");
        };
        return values;
    }
    var colors=new SpecialArray("red","yellow","white");
    alert(colors.toPipedString());//"red|yellow|white"

但這種方式缺點(diǎn)也是很明顯,由于構(gòu)造函數(shù)返回的對(duì)象與構(gòu)造函數(shù)外部創(chuàng)建的對(duì)象沒(méi)有什么不同。所以,instanceof操作符不能確定對(duì)象類型。因此這種模式優(yōu)先級(jí)很低,不推薦優(yōu)先使用。
優(yōu)點(diǎn):可以重寫構(gòu)造函數(shù)函數(shù)的返回值,特殊情況下比較好用。
缺點(diǎn):instanceof操作符不能確定對(duì)象類型。

穩(wěn)妥構(gòu)造函數(shù)模式
    function Person(name) {
        var object=new Object();
        var name=name;
        object.sayName=function () {
            alert(name);
        };
        return object;
    }
    var person=new Person("張三",22,"男");
    person.sayName();//張三
    alert(person.name);//undefined

在這種模式下,想訪問(wèn)name這個(gè)數(shù)據(jù)成員時(shí),除了調(diào)用sayName()方法,沒(méi)有其他方法可以訪問(wèn)傳入構(gòu)造函數(shù)中的原始數(shù)據(jù)。這種模式的安全性就很高。
優(yōu)點(diǎn):安全性高。
缺點(diǎn):instanceof操作符不能確定對(duì)象類型。

繼承 原型鏈
    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());

上面代碼中,我們沒(méi)有使用SubType默認(rèn)提供的原型,而是給它換了一個(gè)新原型(SuperType實(shí)例)。于是,新原型不僅具有作為SuperType的實(shí)例所擁有的全部屬性和方法,而且其內(nèi)部還擁有一個(gè)指針,指向了SuperType的原型。最終結(jié)果如下:

根據(jù)上面,需要說(shuō)明一點(diǎn)的是所有函數(shù)的默認(rèn)原型都是Object的實(shí)例,因此默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針指向Object.prototype。

在我們使用原型鏈的過(guò)程會(huì)有一個(gè)問(wèn)題就是確定原型和實(shí)例之間的關(guān)系。這里我們有兩種方式,我們接著上面代碼繼續(xù)看。

第一種:instanceof操作符,測(cè)試實(shí)例與原型中出現(xiàn)過(guò)的構(gòu)造函數(shù)

    alert(instance instanceof Object);//true
    alert(instance instanceof SuperType);//true
    alert(instance instanceof SubType);//true

第二種:方法isPrototypeOf(),測(cè)試原型鏈中出現(xiàn)過(guò)的原型

   alert(Object.prototype.isPrototypeOf(instance));//true
   alert(SuperType.prototype.isPrototypeOf(instance));//true
   alert(SubType.prototype.isPrototypeOf(instance));//true

如果子類型需要覆蓋超類型中的某個(gè)方法,或者需要添加超類型中不存在的某個(gè)方法,我們要遵循一個(gè)原則,給原型添加方法的代碼一定要放在替換原型的語(yǔ)句之后。如下所示:

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

另外我們還需要注意在添加方法時(shí)候,不能使用對(duì)象字面量創(chuàng)建原型方法。如下所示:

    function SuperType() {
        this.property=true;
    }
    SuperType.prototype.getSuperValue=function () {
        return this.property;
    };
    function SubType() {
        this.subproperty=false;
    }
    //繼承SuperType
    SubType.prototype=new SuperType();
    //使用字面量添加新方法,會(huì)導(dǎo)致上一行代碼無(wú)效
    SubType.prototype={
        getSubValue:function () {
            return this.subproperty;
        }
    };
    var instance=new SubType();
    alert(instance.getSuperValue());
    //Uncaught TypeError: instance.getSuperValue is not a function

說(shuō)到這里我們,我來(lái)總結(jié)一下原型鏈的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):功能很強(qiáng)大,可以連續(xù)繼承多個(gè)原型的全部屬性和方法。
缺點(diǎn):

1.原型的通用問(wèn)題就是屬性被共用,修改原型的屬性將會(huì)動(dòng)態(tài)映射到所有指向該原型的實(shí)例。
2.鑒于屬性是共用的,我們無(wú)法給超類型的構(gòu)造函數(shù)傳遞參數(shù)。
借用構(gòu)造函數(shù)
    function SuperType() {
        this.colors=["red","blue","green"];
    }
    function SubType() {
        //繼承了SuperType
        SuperType.call(this);
    }
    var instance1=new SubType();
    instance1.colors.push("black");
    console.log(instance1.colors);//["red", "blue", "green", "black"]
    var instance2=new SubType();
    console.log(instance2.colors);//["red", "blue", "green"]

通過(guò)使用call()方法(或apply()方法),在新建的SubType實(shí)例的環(huán)境下條用了SuperType構(gòu)造函數(shù)。這樣一來(lái),就會(huì)在新的SubType對(duì)象上執(zhí)行SuperType()函數(shù)中定義的所有對(duì)象初始化代碼。結(jié)果,SubType的每個(gè)實(shí)例就都會(huì)具有自己的colors屬性的副本了。

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

    function SuperType(name) {
        this.name=name;
    }
    function SubType() {
        //繼承了SuperType,同時(shí)還傳遞了參數(shù)
        SuperType.call(this,"張三");
        //實(shí)例屬性
        this.age=22;
    }
    var instance=new SubType();
    alert(instance.name);//張三
    alert(instance.age);//22

優(yōu)點(diǎn):彌補(bǔ)原型鏈的共用屬性和不能傳遞參數(shù)的缺點(diǎn)。
缺點(diǎn):函數(shù)不能復(fù)用,超類型的原型中定義的方法在子類型中是不可見的。

組合繼承
    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);//第二次調(diào)用SuperType()
        this.age=age;
    }
    //繼承方法
    SubType.prototype=new SuperType();
    SubType.prototype.constructor=SubType;
    SubType.prototype.sayAge=function () {
      alert(this.age);
    };
    var instance1=new SubType("張三",22);//第一次調(diào)用SuperType()
    instance1.colors.push("black");
    console.log(instance1.colors);//["red", "blue", "green", "black"]
    instance1.sayName();//張三
    instance1.sayAge();//22


    var instance2=new SubType("李四",25);
    console.log(instance2.colors);//["red", "blue", "green"]
    instance2.sayName();//李四
    instance2.sayAge();//25
    

缺點(diǎn):創(chuàng)建對(duì)象時(shí)都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù)。
優(yōu)點(diǎn):融合了原型鏈和借助構(gòu)造函數(shù)的優(yōu)點(diǎn),避免了他們的缺陷。Javascript中最常用的繼承模式。

原型式繼承
    var person={
        name:"張三",
        friends:["李四","王五"]
    };
    var person1=Object(person);//或者Object.create(person)
    person1.name="趙六";
    person1.friends.push("孫七");
    var person2=Object.create(person);
    person2.name="周八";
    person2.friends.push("吳九");
    console.log(person.friends);//["李四", "王五", "孫七", "吳九"]

原型式繼承實(shí)際上是把實(shí)例的__proto__屬性指向了person。

優(yōu)點(diǎn):只想讓一個(gè)對(duì)象跟另一個(gè)對(duì)象保持相似的情況下,代碼變得很簡(jiǎn)單。
缺點(diǎn):共享了相應(yīng)的值,原型的通病。

寄生式繼承
    function createPerson(obj) {
        var clone=Object(obj);
        clone.sayMyfriends=function () {
            console.log(this.friends);
        };
        return clone;
    }
    var person={
        name:"張三",
        friends:["李四","王五","趙六"]
    };
    var anotherPerson= createPerson(person);
    anotherPerson.sayMyfriends();//["李四", "王五", "趙六"]

優(yōu)點(diǎn):可以為任意對(duì)象添加指定屬性,代碼量很少。
缺點(diǎn): 在為對(duì)象添加函數(shù),由于函數(shù)不能復(fù)用。每次添加都會(huì)新建一個(gè)函數(shù)對(duì)象,降低了效率。這一點(diǎn)與構(gòu)造函數(shù)模式類似。

寄生組合式繼承
    function inheritPrototype(subType,superType) {
        var prototype=Object(superType.prototype);//創(chuàng)建對(duì)象
        prototype.constructor=subType;//增強(qiáng)對(duì)象
        subType.prototype=prototype;//指定對(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);
    };
    var instance1=new SubType("張三",22);
    instance1.colors.push("yellow");
    instance1.sayName();//張三
    instance1.sayAge();//22

    var instance2=new SubType("李四",25);
    console.log(instance2.colors);// ["red", "blue", "green"]
    instance2.sayName();//李四
    instance2.sayAge();//25

上面的inheritPrototype()函數(shù)接收兩個(gè)參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。在函數(shù)內(nèi)部,第一部是創(chuàng)建超類型原型的一個(gè)副本。第二步是為創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)因重寫原型而失去的默認(rèn)的constructor屬性。最后一步,將新創(chuàng)建的對(duì)象(即副本)賦值給子類型的原型。這樣,我們就可以用調(diào)用inheritPrototype()函數(shù)的語(yǔ)句,去替換前面例子中為子類型原型賦值的語(yǔ)句。
優(yōu)點(diǎn):集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身,是實(shí)現(xiàn)基于類型繼承的最有效方式。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/83374.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    李昌杰 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    Lyux 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類是相似對(duì)象的描述,稱為類的定義,是該類對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類的實(shí)體化形成的對(duì)象。一類的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

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

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

    novo 評(píng)論0 收藏0
  • javascript 面向對(duì)象版塊之理解對(duì)象

    摘要:用代碼可以這樣描述安全到達(dá)國(guó)外面向過(guò)程既然說(shuō)了面向?qū)ο?,那么與之對(duì)應(yīng)的就是面向過(guò)程。小結(jié)在這篇文章中,介紹了什么是面向?qū)ο蠛兔嫦蜻^(guò)程,以及中對(duì)象的含義。 這是 javascript 面向?qū)ο蟀鎵K的第一篇文章,主要講解對(duì)面向?qū)ο笏枷氲囊粋€(gè)理解。先說(shuō)說(shuō)什么是對(duì)象,其實(shí)這個(gè)還真的不好說(shuō)。我們可以把自己當(dāng)成一個(gè)對(duì)象,或者過(guò)年的時(shí)候相親,找對(duì)象,那么你未來(lái)的老婆也是一個(gè)對(duì)象。我們就要一些屬性,比...

    lovXin 評(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í)世界的一種方式。除了字面式聲明方式之外,允許通過(guò)構(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

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

0條評(píng)論

閱讀需要支付1元查看
<