溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

發(fā)布時間:2020-06-10 16:19:27 來源:網(wǎng)絡(luò) 閱讀:313 作者:吳金瑞 欄目:網(wǎng)絡(luò)安全

    

我們創(chuàng)建的每個函數(shù)都有一個prototype屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,通俗的講,prototype就是通過構(gòu)造函數(shù)創(chuàng)建的實例對象的原型對象,使用原型對象的好處是可以讓所有的實例對象共享它的屬性和方法

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2         Person.prototype.name = "Nicholas"; 3         Person.prototype.age = 29; 4         Person.prototype.job = "Software Engineer"; 5         Person.prototype.sayName = function(){ 6             console.log(this.name); 7         }; 8     }; 9 10     var person1 = new Person();11     person1.sayName(); //Nicholas12 13     var person2 = new Person();14     person2.sayName(); //Nicholas15 16     console.log(person1.sayName == person2.sayName); //true

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

1、理解原型對象
無論什么時候,只要創(chuàng)建了一個新的函數(shù),就會根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象。在默認情況下,原型對象有一個constructor屬性,指向prototype屬性所在的函數(shù)指針

isPrototypeOf()方法可以確定對象之間是否存在這種關(guān)系

 

1     console.log(Person.prototype.isPrototypeOf(person1)); //true

 

ECMAScript5新增加了一個方法Object.getPrototypeOf()

 

1 console.log(Object.getPrototypeOf(person1));//Object {name: "Nicholas", age: 29, job: "Software Engineer"}

 

每當代碼讀取某個對象的某個屬性時,都會執(zhí)行一次搜索。首先搜索從對象實例本身開始。如果在實例對象本身找到了具有給定名字的屬性,則返回該屬性的值,如果沒有找到,在繼續(xù)搜索指針指向的原型對象

雖然可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例改寫原型中的值,使用delete可以完全刪除實例屬性,從而讓我們能夠重新訪問原型中的屬性

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2         Person.prototype.name = "Nicholas"; 3         Person.prototype.age = 29; 4         Person.prototype.job = "Software Engineer"; 5         Person.prototype.sayName = function(){ 6             console.log(this.name); 7         }; 8     }; 9 10     var person1 = new Person();11 12     var person2 = new Person();13 14     person1.name = "Greg";15     console.log(person1.name); //Greg16     console.log(person2.name); //Nicholas17 18     delete person1.name;19     console.log(person1.name); //Nicholas

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

hasOwnProperty()方法可以檢測一個屬性是否在實例中,還是在原型中,在實例中返回true

 

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2         Person.prototype.name = "Nicholas"; 3         Person.prototype.age = 29; 4         Person.prototype.job = "Software Engineer"; 5         Person.prototype.sayName = function(){ 6             console.log(this.name); 7         }; 8     }; 9 10     var person1 = new Person();11     var person2 = new Person();12     console.log(person1.hasOwnProperty("name")); //false13     person2.name = "Greg";14     console.log(person2.hasOwnProperty("name")); //true

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

2、原型與in操作符

有兩種方式使用in操作符,單獨使用和在for-in中使用,單獨使用時,in操作符在通過對象能夠訪問到指定屬性時返回true,無論在實例中還是在原型中

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2         Person.prototype.name = "Nicholas"; 3         Person.prototype.age = 29; 4         Person.prototype.job = "Software Engineer"; 5         Person.prototype.sayName = function(){ 6             console.log(this.name); 7         }; 8     }; 9 10     var person1 = new Person();11     var person2 = new Person();12     console.log(person1.hasOwnProperty("name")); //false13     console.log("name" in person1); //true14     person1.name = "Greg";15     console.log(person1.hasOwnProperty("name")); //true16     console.log("name" in person1); //true

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

同時使用hasOwnProperty()和in操作符,就可以確定該屬性到底是存在于實例中還是存在于原型中

 

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function hasPrototypeProperty(object,name){ 2         return (!object.hasOwnProperty(name) && (name in object)); 3     } 4  5     //hasPrototypeProperty()返回true則表示該屬性在原型中 6  7     function Person(){ 8         Person.prototype.name = "Nicholas"; 9         Person.prototype.age = 29;10         Person.prototype.job = "Software Engineer";11         Person.prototype.sayName = function(){12             console.log(this.name);13         };14     };15 16     var person3 = new Person();17     console.log(hasPrototypeProperty(person3,"job")); //true18     person3.job = "Teacher";19     console.log(hasPrototypeProperty(person3,"job")); //false

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

 

在使用for-in循環(huán)時,返回的是所有能夠通過對象訪問的,可枚舉屬性,其中包括在實例中的屬性、原型中的屬性、屏蔽了原型中不可枚舉屬性的實例屬性。

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

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2         Person.prototype.name = "Nicholas"; 3         Person.prototype.age = 29; 4         Person.prototype.job = "Software Engineer"; 5         Person.prototype.sayName = function(){ 6             console.log(this.name); 7         }; 8     }; 9 10     // Object.defineProperties(Person.prototype,{11     //     name:{12     //         enumerable: true,13     //     },14     //     age:{15     //         enumerable: true,16     //     },17     // });18 19     var keys = Object.keys(Person.prototype);20     console.log(keys);21     var person1 = new Person();22     person1.name = "Greg";23     person1.age = 22;24     var person1Keys = Object.keys(person1);25     console.log(person1Keys);

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

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

1     var keys = Object.getOwnPropertyNames(Person.prototype);2     console.log(keys); //["constructor", "name", "age", "job", "sayName"]

 

 

3、更簡單的原型語法
是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2  3     } 4  5     Person.prototype = { 6         name : "Nicholas", 7         age : 29, 8         job : "SoftWare Engineer", 9         sayName : function(){10             console.log(this.name);11         },12     };

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

這里使用的語法,本質(zhì)上完全重寫了默認的prototype對象,因此constructor屬性也就變成了新對象的constructor屬性(指向Object構(gòu)造函數(shù)),此時盡管instanceof操作符還能返回正確的結(jié)果,但通過constructor已經(jīng)無法確定對象的類型了

1     var friend = new Person();2 3     console.log(friend instanceof Object); //true4     console.log(friend instanceof Person); //true5     console.log(friend.constructor == Person); //false6     console.log(friend.constructor == Object); //true

可見此時的constructor屬性等于Object,如果constructor的值很重要,可以將它設(shè)置為適當?shù)闹?/span>

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2  3     } 4  5     Person.prototype = { 6         constructor : Person, 7         name : "Nicholas", 8         age : 29, 9         job : "SoftWare Engineer",10         sayName : function(){11             console.log(this.name);12         },13     };

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

注意:以這種方式重設(shè)constructor屬性會導致他的`Enumerable`特性被設(shè)置為true。默認情況下,原生的
constructor屬性是不可枚舉的

 

4、原型的動態(tài)性

1     var friend = new Person();2     Person.prototype.sayHi = function(){3         alert("hi");4     };5     friend.sayHi(); //hi

 

雖然friend實例是在添加新方法之前創(chuàng)建的,但是它可以訪問這個方法,原因在于每當代碼讀取某個對象的某個屬性時,都會執(zhí)行一次搜索。首先搜索從對象實例本身開始。如果在實例對象本身找到了具有給定名字的屬性,則返回該屬性的值,如果沒有找到,在繼續(xù)搜索指針指向的原型對象

盡管可以隨時為原型添加屬性和方法,并且修改能夠立即在所有對象實例中反映出來,如果是重新寫整個原型對象,那么情況就不一樣了

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2     } 3  4     var friend = new Person(); 5  6     Person.prototype = { 7         constructor : Person, 8         name : "Nicholas", 9         age : 29,10         job : "SoftWare Engineer",11         sayName : function(){12             console.log(this.name);13         },14     };15 16     friend.sayName(); //error

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

 

5、原生對象模型
通過對原生對象的原型,不僅可以取得所有默認方法的引用,而且也可以定義新方法

1     String.prototype.ll = function(text){2         return text.length;3     };4     var msg = "Hello";5     console.log(msg.ll("SoftWare")); //8

 

6、原型對象的問題
首先,它省略了為構(gòu)造函數(shù)傳遞參數(shù)這一環(huán)節(jié),結(jié)果所有的實例在默認情況下都將取得相同的屬性值。原型模式最大的問題是由共享的本性所導致的,對于包含基本值的屬性可以再實例中添加一個同名屬性而對于包含引用類型的屬性來說,問題就比較突出了

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(){ 2     } 3  4     Person.prototype = { 5         constructor : Person, 6         name : "Nicholas", 7         age : 29, 8         job : "SoftWare Engineer", 9         friend : ["Shelby","Court"],10         sayName : function(){11             console.log(this.name);12         },13     };14 15     var person1 = new Person();16     var person2 = new Person();17 18     person1.friend.push("Van");19     console.log(person1.friend); //["Shelby", "Court", "Van"]20     console.log(person2.friend); //["Shelby", "Court", "Van"]21     console.log(person1.friend ==person2.friend); //true

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

而這個問題正是我們看到很少有人單獨使用原型模式的原因所在

 

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


 

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(name,age,job){ 2         this.name = name; 3         this.age = age; 4         this.job = job; 5         this.friend = ["Shelby","Court"]; 6     } 7  8     Person.prototype = { 9         constructor : Person,10         sayName : function(){11             console.log(this.name);12         },13     };14 15     var person1 = new Person();16     var person2 = new Person();17 18     person1.friend.push("Van");19     console.log(person1.friend); //["Shelby", "Court", "Van"]20     console.log(person2.friend); //["Shelby", "Court"]21     console.log(person1.sayName === person2.sayName); //true

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

這是目前在ECMAScript中使用最廣泛的一種創(chuàng)建自定義類型的方法,可以說,這是用來定義引用類型的一種默認模式

動態(tài)原型模式


把所有信息都封裝在構(gòu)造函數(shù)中,而通過在構(gòu)造函數(shù)中初始化原型,又保持了同時使用構(gòu)造函數(shù)和原型的優(yōu)點

 

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(name,age,job){ 2         this.name = name; 3         this.age = age; 4         this.job = job; 5         if(typeof this.sayName != "function"){  //只有在初次調(diào)用構(gòu)造函數(shù)時才會執(zhí)行 6             Person.prototype.sayName = function(){ 7                 console.log(this.name); 8             }; 9         };10     };11 12     var friend = new Person("Nicholas",29,"Software Engineer");13     friend.sayName(); //Nicholas

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

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


 

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function Person(name,age,job){ 2         var o = new Object(); 3         o.name = name; 4         o.age = age; 5         o.job = job; 6         o.sayName = function(){ 7             console.log(this.name); 8         }; 9         return o;10     }11 12     var friend = new Person("Nicholas",29,"Software Engineer");13     friend.sayName(); //Nicholas

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

   這個模式在特殊情況下來為對象創(chuàng)建構(gòu)造函數(shù),假設(shè)我們想創(chuàng)建一個具有額外方法的特殊數(shù)組

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1     function SpecialArray(){ 2         var values = new Array(); 3         values.push.apply(values,arguments); 4         values.toPipedString = function(){ 5             return this.join("|"); 6         }; 7         return values; 8     }; 9 10     var colors = new SpecialArray("red","blue","green");11     console.log(colors.toPipedString()); //red|blue|green

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 

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


 所謂穩(wěn)妥對象,值得是沒有公共屬性,而且其方法也不引用this對象

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

 1    function Person(name,age,job){ 2  3        //創(chuàng)建要返回的對象 4        var o = new Object(); 5  6        //可以再這里定義私有變量和函數(shù) 7  8        //添加方法 9        o.sayName = function(){10            console.log(name);11        };12 13        //返回對象14        return o;15 16    };17 18    var friend = Person("Nicholas",29,"Software Engineer");19    friend.sayName(); //Nicholas

面向?qū)ο蟮某绦蛟O(shè)計-原型模式

  這樣,變量friend中保存著一個穩(wěn)妥對象,而除了調(diào)用sayName()方法外,沒有別的方式可以訪問其數(shù)據(jù)成員。


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI