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

資訊專欄INFORMATION COLUMN

基礎(chǔ)二:javascript面向?qū)ο蟆?chuàng)建對(duì)象、原型和繼承總結(jié)(上)

fevin / 3339人閱讀

摘要:創(chuàng)建對(duì)象兩個(gè)基本方法創(chuàng)建對(duì)象最基本的兩個(gè)方法是構(gòu)造函數(shù)和對(duì)象字面量。當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新的實(shí)例對(duì)象后,該實(shí)例內(nèi)部會(huì)有一個(gè)指針指向構(gòu)造函數(shù)的原型對(duì)象。碼農(nóng)構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象實(shí)例。

前言:本文主要總結(jié)一下javascript創(chuàng)建對(duì)象的方法、原型、原型鏈和繼承,但是先從創(chuàng)建對(duì)象的幾種方法開(kāi)始,延伸到原型模式創(chuàng)建對(duì)象以及其它模式。繼承本來(lái)想一塊寫了,發(fā)現(xiàn)太多內(nèi)容了,放到下里總結(jié)。

1.創(chuàng)建對(duì)象 (1)兩個(gè)基本方法

創(chuàng)建對(duì)象最基本的兩個(gè)方法是:Object構(gòu)造函數(shù)對(duì)象字面量

    //Object構(gòu)造函數(shù)方式
    var person = new Object();
    person.name = "Jack";
    person.age = 12;
    person.sayName = function(){
        alert(this.name);
    };
    
    //字面量方式
    var person = {
        name: "Jack",
        age: 14,
        job: "碼農(nóng)",
        sayName: function(){
            alert(this.name);
        }
    };
(2)工廠模式

上述兩個(gè)基本方法的缺點(diǎn)是:使用同一個(gè)接口創(chuàng)建很多對(duì)象,會(huì)產(chǎn)生大量的復(fù)制代碼。針對(duì)這個(gè)缺點(diǎn),看下面
原理是用函數(shù)來(lái)封裝以特定接口創(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("Jack",15,"碼農(nóng)");
    var person2 = createPerson("rose",12,"程序媛");

函數(shù)createPerson能接收參數(shù)構(gòu)建一個(gè)包含所有屬性的對(duì)象,并且可以用很少的代碼不斷的創(chuàng)建多個(gè)對(duì)象,但是由于它被函數(shù)所封裝,暴露的接口不能有效的識(shí)別對(duì)象的類型(即你不知道是Object還是自定義的什么對(duì)象)。

(3)構(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("Jack",15,"碼農(nóng)");  //滿滿的java復(fù)古風(fēng)
    var person2 = new Person("Rose",15,"程序媛");

與工廠模式相比,構(gòu)造函數(shù)模式用Person()函數(shù)代替了createPerson()函數(shù),并且沒(méi)有顯示的創(chuàng)建對(duì)象,直接把屬性和方法賦值給了this對(duì)象。

要?jiǎng)?chuàng)建Person的實(shí)例,必須使用new關(guān)鍵字。

person1和person2都是Person的實(shí)例,這兩個(gè)對(duì)象都有一個(gè)constructor(構(gòu)造函數(shù))屬性,該屬性指向Person。 person1.constructor == Person; //true

person1即是Person的實(shí)例又是Object的實(shí)例,后面繼承原型鏈會(huì)總結(jié)。

(3).1構(gòu)造函數(shù)的使用
     //當(dāng)做構(gòu)造函數(shù)使用
     var person1 = new Person("Jack",15,"碼農(nóng)");
     person1.sayName();   //"Jack"
     
     //當(dāng)做普通函數(shù)使用
     Person("Jack",16,"碼農(nóng)");     //注意:此處添加到了window
     window.sayName();  //"Jack"
     
     //在另一個(gè)對(duì)象的作用域中調(diào)用
     var o = new Object();
     Person.call(o,"Jack",12,"碼農(nóng)");
     o.sayName();   //"Jack"

第一種當(dāng)做構(gòu)造函數(shù)使用就不多說(shuō)了

當(dāng)在全局作用域中調(diào)用Person("Jack",16,"碼農(nóng)");時(shí),this對(duì)象總是指向Global對(duì)象(瀏覽器中是window對(duì)象)。因此在執(zhí)行完這句代碼后,可以通過(guò)window對(duì)象來(lái)調(diào)用sayName()方法,并且返回“Jack”。

最后也可以使用call()或者apply()在某個(gè)特殊對(duì)象的作用域中調(diào)用Person()函數(shù)

(3).2存在的問(wèn)題

在(3)構(gòu)造函數(shù)模式的代碼中,對(duì)象的方法sayName的功能都一樣,就是alert當(dāng)前對(duì)象的name。當(dāng)實(shí)例化Person之后,每個(gè)實(shí)例(person1和person2)都有一個(gè)名為sayName的方法,但是兩個(gè)方法不是同一個(gè)Function實(shí)例。不要忘了,js中函數(shù)是對(duì)象,所以每個(gè)實(shí)例都包含一個(gè)不同的Function實(shí)例,然而創(chuàng)建兩個(gè)功能完全一樣的Function實(shí)例是完全沒(méi)有必要的。因此可以把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外。
如下代碼:

     function Person(name,age,job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = sayName;
        }
    function sayName(){
            alert(this.name);
        }
        
    //實(shí)例化對(duì)象
    var person1 = new Person("Jack",15,"碼農(nóng)");  //滿滿的java復(fù)古風(fēng)
    var person2 = new Person("Rose",15,"程序媛");

但是這樣依然存在問(wèn)題:

為了讓Person的實(shí)例化對(duì)象共享在全局作用域中定義的同一個(gè)sayName()函數(shù),我們把函數(shù)sayName()定義在全局作用域中,并通過(guò)指針sayName指向構(gòu)造函數(shù),所以在全局作用域中的sayName()只能被特定對(duì)象調(diào)用,全局作用域名不符實(shí),且污染全局變量。

并且如果對(duì)象需要很多種方法,那么就要定義很多全局函數(shù),對(duì)于對(duì)象就沒(méi)有封裝性,并且污染全局。

2.原型 (1)原型模式創(chuàng)建對(duì)象

js不同于強(qiáng)類型語(yǔ)言的java,java創(chuàng)建對(duì)象的過(guò)程是由類(抽象)到類的實(shí)例的過(guò)程,是一個(gè)從抽象到具體的過(guò)程。

javascript則不同,其用原型創(chuàng)建對(duì)象是一個(gè)具體到具體的過(guò)程,即以一個(gè)實(shí)際的實(shí)例為藍(lán)本(原型),去創(chuàng)建另一個(gè)實(shí)例對(duì)象。

所以用原型模式創(chuàng)建對(duì)象有兩種方式:

1.Object.create()方法
Object.create:它接收兩個(gè)參數(shù),第一個(gè)是用作新對(duì)象原型的對(duì)象(即原型),一個(gè)是為新對(duì)象定義額外屬性的對(duì)象(可選,不常用)。

    var Person = {
        name:"Jack",
        job:"碼農(nóng)"
    };
    //傳遞一個(gè)參數(shù)
    var anotherPerson = Object.create(Person);
    anotherPerson.name     //"Jack"
    //傳遞兩個(gè)參數(shù)
    var yetPerson = Object.create(Person,{name:{value:"Rose"}});
    yetPerson.name;        //Rose
    

2.構(gòu)造函數(shù)方法創(chuàng)建對(duì)象

任何一個(gè)函數(shù)都有一個(gè)prototype屬性(是一個(gè)指針),指向通過(guò)構(gòu)造函數(shù)創(chuàng)建的實(shí)例對(duì)象原型對(duì)象,原型對(duì)象可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。

因此不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是將這些屬性和方法直接添加到原型對(duì)象中,從而被實(shí)例對(duì)象多繼承(繼承后面總結(jié))

    //第一步:用構(gòu)造函數(shù)創(chuàng)建一個(gè)空對(duì)象
    function Person(){
    }
    //第二步:給原型對(duì)象設(shè)置屬性和方法
    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "碼農(nóng)";
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    //第三步:實(shí)例化對(duì)象后,便可繼承原型對(duì)象的方法和屬性
    var person1 = new Person();
    person1.sayName();           //Jack
    
    var person2 = new Person();
    person2.sayName();           //Jack
    
    alert(person1.sayName == person2.sayName);   //true

person1和person2說(shuō)訪問(wèn)的是同一組屬性和同一個(gè)sayName()函數(shù)。

(2)理解原型對(duì)象

只要?jiǎng)?chuàng)建一個(gè)函數(shù),就會(huì)為該函數(shù)創(chuàng)建一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。

所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向prototype屬性所在函數(shù)的指針。

當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新的實(shí)例對(duì)象后,該實(shí)例內(nèi)部會(huì)有一個(gè)指針([prototype]/_proto_),指向構(gòu)造函數(shù)的原型對(duì)象。如下圖:

上圖中 :

Person.prototype指向了原型對(duì)象,而Person.prototype.construstor又指回了Person。

注意觀察原型對(duì)象,除了包含constructor屬性之外,還包括后來(lái)添加的其它屬性,這就是為什么每個(gè)實(shí)例化后的對(duì)象,雖然都不包含屬性和方法,但是都包含一個(gè)內(nèi)部屬性指向了Person.prototype,能獲得原型中的屬性和方法。

(3)判斷一個(gè)實(shí)例對(duì)象的原型

這個(gè)方法叫:Object.getPrototypeOf(),如下例子:

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

這個(gè)方法可以很方便的取得一個(gè)對(duì)象的原型

還可以利用這個(gè)方法取得原型對(duì)象中的name屬性的值。

(3)搜索屬性的過(guò)程

當(dāng)我們?cè)趧?chuàng)建實(shí)例化的對(duì)象之后,調(diào)用這個(gè)實(shí)例化的對(duì)象的屬性時(shí),會(huì)先后執(zhí)行兩次搜索。

第一次搜索實(shí)例person1有name屬性嗎?沒(méi)有進(jìn)行第二次搜索

第二次搜索person1的原型有name屬性嗎?有就返回。

因此進(jìn)行一次思考,如果對(duì)實(shí)例進(jìn)行屬性重寫和方法覆蓋之后,訪問(wèn)實(shí)例對(duì)象的屬性和方法會(huì)顯示哪個(gè)?實(shí)例對(duì)象的還是對(duì)象原型的?

    function Person(){
    }
    
    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "碼農(nóng)";
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    
    var person1 = new Person();
    var person2 = new Person();
    
    person1.name = "Rose";
    alert(person1.name);        //Rose
    alert(person2.name);       //Jack
    

當(dāng)為對(duì)象實(shí)例添加一個(gè)屬性時(shí),這個(gè)屬性就會(huì)屏蔽原型對(duì)象中保存的同名屬性。

但是這個(gè)屬性只會(huì)阻止我們?cè)L問(wèn)原型中的那個(gè)屬性,而不會(huì)修改那個(gè)屬性
3.使用delete操作符可以刪除實(shí)例屬性,從而重新訪問(wèn)原型中的屬性。

    function Person(){
    }

    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "碼農(nóng)";
    Person.prototype.sayName = function(){
        alert(this.name);
    };

    var person1 = new Person();
    var person2 = new Person();
    
    person1.name = "Rose";
    alert(person1.name);        //Rose  --來(lái)自實(shí)例
    alert(person2.name);       //Jack  --來(lái)自原型
    
    delete person1.name;
    alert(person1.name);      //Jack  --來(lái)自原型
    
(4)判斷訪問(wèn)的到底是對(duì)象還是原型屬性

hasOwnProperty()可以檢測(cè)一個(gè)屬性是存在于實(shí)例中,還是原型中,只有在給定屬性存在于對(duì)象實(shí)例中,才會(huì)返回true。

person1.hasOwnProperty("name");    //假設(shè)name存在于原型,返回false

in操作符會(huì)在通過(guò)對(duì)象能夠訪問(wèn)給定屬性時(shí)返回true,無(wú)論該屬性是存在于實(shí)例中還是原型中

"name" in person1   //true

所以通過(guò)這兩個(gè)可以封裝一個(gè)hasPrototypeProperty()函數(shù)確定屬性是不是原型中的屬性。

function hasPrototypeProperty(object,name){
    return !object.hasOwnProperty(name) && (name in object); 
}
(5)更簡(jiǎn)單的原型語(yǔ)法

前面每次添加一個(gè)屬性和方法都要寫一次Person.prototype,為了簡(jiǎn)便可以直接這樣

    function Person(){
    }
    Person.prototype = {
        name:"Jack",
        age:20,
        job:"碼農(nóng)",
        sayName:function(){
            alert("this.name");
        }
    };
    

上述代碼直接將Person.prototype設(shè)置為等于一個(gè)以對(duì)象字面量形式創(chuàng)建的新對(duì)象

上述這么做時(shí):constructor屬性就不再指向Person了。

本質(zhì)上完全重寫了默認(rèn)的prototype對(duì)象,因此constructor屬性也就變成了新對(duì)象的constructor屬性(指向Object構(gòu)造函數(shù))。

因此如果constructor值很重要,可以在Person.prototype中設(shè)置回適當(dāng)?shù)闹担?br>如上例中可以添加:constructor:Person,

(6)原型的動(dòng)態(tài)性

我們對(duì)原型對(duì)象所做的任何修改都會(huì)立即從實(shí)例上反映出來(lái)-即使先創(chuàng)建實(shí)例對(duì)象后修改原型也如此

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

盡管可以隨時(shí)為原型添加屬性和方法,并且修改能立即在實(shí)例對(duì)象中體現(xiàn)出來(lái),但是如果重寫整個(gè)原型對(duì)象,就不一樣了。看下面例子:

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

上述代碼先創(chuàng)建了一個(gè)Person實(shí)例,然后又重寫了其原型對(duì)象,在調(diào)用friend.sayName()時(shí)發(fā)生錯(cuò)誤。

因?yàn)閒riend指向的原型中不包含以該名字命名的屬性。關(guān)系如下圖:

(7)原型對(duì)象的問(wèn)題

省略了為構(gòu)造函數(shù)初始化參數(shù)這一環(huán)節(jié),結(jié)果是所有實(shí)例都取得相同的屬性,但問(wèn)題不大,可以為實(shí)例對(duì)象重寫屬性來(lái)解決。
2.但是,對(duì)于包含引用類型值的屬性來(lái)說(shuō),問(wèn)題就比較突出了,因?yàn)橐妙愋椭?,屬性名只是一個(gè)指針,在實(shí)例中重寫該屬性并沒(méi)有作用。指針始終指向原來(lái)的。

如下例子:

function Person(){}

    Person.prototype = {
        constructor:Person,
        name:"Jack",
        job:"碼農(nóng)",
        friends:["路人甲","路人乙","路人丙"],
    
    };
    var person1 = new Person();
    var person2 = new Person();
    
    person1.friends.push("路人丁");
    alert(person1.friends);     //["路人甲","路人乙","路人丙","路人丁"]
    alert(person2.friends);    //["路人甲","路人乙","路人丙","路人丁"]
    alert(person1.friends === person2.friends);     //true

上面這個(gè),假如每個(gè)實(shí)例對(duì)象的引用值屬性不一樣,則無(wú)法修改。

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

構(gòu)造函數(shù)模式用于定義實(shí)例屬性

原型模式用于定義方法和共享的屬性

如下代碼:

    function Person(name,age,job){
        this.name = name;
        this.job = job;
        this.age = age;
        this.friends = ["路人甲","路人乙"];
    }
    
    Person.prototype = {
        constructor:Person,
        sayName: function(){
            alert(this.name);
        }
    }
    var person1 = new Person("Jack", 20, "碼農(nóng)");
    var person2 = new Person("Rose", 20, "程序媛");
    
    person1.friends.push("路人丁");
    alert(person1.friends);                  //["路人甲","路人乙","路人丁"]
    alert(person2.friends);                  //["路人甲","路人乙"]
    alert(person1.friends === person2.friends);     //false
    alert(person1.sayName === person2.sayName);    //true
4.寄生構(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("Jack", 16, "碼農(nóng)");
    friend.sayName();          //Jack

構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象實(shí)例。

通過(guò)在構(gòu)造函數(shù)末尾添加一個(gè)return語(yǔ)句,可以重寫調(diào)用構(gòu)造函數(shù)時(shí)返回的值。

這個(gè)方法的用處是:可以創(chuàng)建一個(gè)額外方法的特殊的數(shù)組(因?yàn)樵鷮?duì)象Array的構(gòu)造函數(shù)不能直接修改)

       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("black","red","blue");    
        alert(colors.toPipedString());
    

本來(lái)想接著寫繼承的,發(fā)現(xiàn)實(shí)在太多了,分成兩篇吧。

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

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

相關(guān)文章

  • 基礎(chǔ)javascript面向對(duì)象、創(chuàng)建對(duì)象原型繼承總結(jié)(下)

    摘要:當(dāng)調(diào)用的構(gòu)造函數(shù)時(shí),在函數(shù)內(nèi)部又會(huì)調(diào)用的構(gòu)造函數(shù),又在新對(duì)象上創(chuàng)建了實(shí)例屬性和,于是這兩個(gè)屬性就屏蔽了原型中的同名屬性。 前言:這次對(duì)上篇收個(gè)尾,主要總結(jié)一下javascript的繼承。 1.原型鏈 js中原型鏈?zhǔn)菍?shí)現(xiàn)繼承的主要方法。基本思想是:利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。我們來(lái)簡(jiǎn)單回顧一下以前的內(nèi)容: 每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象 每個(gè)原型對(duì)象都包含一個(gè)指...

    617035918 評(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); 馬上就要到七夕了,離年底老媽老爸...

    李昌杰 評(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
  • 總結(jié)javascript基礎(chǔ)概念(三):js對(duì)象原型

    摘要:執(zhí)行構(gòu)造函數(shù)的一步說(shuō)明對(duì)象可以通過(guò)函數(shù)來(lái)創(chuàng)建。是最頂級(jí)的構(gòu)造函數(shù),對(duì)象里面,就有好幾個(gè)其他屬性。構(gòu)造函數(shù)與普通函數(shù)并沒(méi)有區(qū)別,只是調(diào)用方式不同。 主要問(wèn)題:1、構(gòu)造函數(shù)和普通函數(shù)有區(qū)別么?什么區(qū)別?2、prototype和__proto__有什么不同?3、instanceof的作用機(jī)制,為什么有限制?4、ES6的相關(guān)方法,Class繼承原理? 三、對(duì)象與原型 (一)、數(shù)據(jù)類型 Js...

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

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

0條評(píng)論

閱讀需要支付1元查看
<