温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

面向对象的程序设计-原型模式

发布时间:2020-06-10 16:19:27 来源:网络 阅读:308 作者:吴金瑞 栏目:网络安全

    

我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,通俗的讲,prototype就是通过构造函数创建的实例对象的原型对象,使用原型对象的好处是可以让所有的实例对象共享它的属性和方法

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

1、理解原型对象
无论什么时候,只要创建了一个新的函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,原型对象有一个constructor属性,指向prototype属性所在的函数指针

isPrototypeOf()方法可以确定对象之间是否存在这种关系

 

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

 

每当代码读取某个对象的某个属性时,都会执行一次搜索。首先搜索从对象实例本身开始。如果在实例对象本身找到了具有给定名字的属性,则返回该属性的值,如果没有找到,在继续搜索指针指向的原型对象

虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例改写原型中的值,使用delete可以完全删除实例属性,从而让我们能够重新访问原型中的属性

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

hasOwnProperty()方法可以检测一个属性是否在实例中,还是在原型中,在实例中返回true

 

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

2、原型与in操作符

有两种方式使用in操作符,单独使用和在for-in中使用,单独使用时,in操作符在通过对象能够访问到指定属性时返回true,无论在实例中还是在原型中

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

同时使用hasOwnProperty()和in操作符,就可以确定该属性到底是存在于实例中还是存在于原型中

 

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

 

在使用for-in循环时,返回的是所有能够通过对象访问的,可枚举属性,其中包括在实例中的属性、原型中的属性、屏蔽了原型中不可枚举属性的实例属性。

要取得对象上所有可枚举的属性,可以使用ECMAScript5的Object.keys()方法,这个方法接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。

面向对象的程序设计-原型模式

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

面向对象的程序设计-原型模式

 

如果想要得到所有的实例属性,无论它是否可枚举,都可以使用Object.getOwnPropertyNames()方法

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

 

 

3、更简单的原型语法
是用一个包含所有属性和方法的对象字面量来重写整个原型对象

面向对象的程序设计-原型模式

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

面向对象的程序设计-原型模式

 

这里使用的语法,本质上完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数),此时尽管instanceof操作符还能返回正确的结果,但通过constructor已经无法确定对象的类型了

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的值很重要,可以将它设置为适当的值

面向对象的程序设计-原型模式

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

面向对象的程序设计-原型模式

注意:以这种方式重设constructor属性会导致他的`Enumerable`特性被设置为true。默认情况下,原生的
constructor属性是不可枚举的

 

4、原型的动态性

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

 

虽然friend实例是在添加新方法之前创建的,但是它可以访问这个方法,原因在于每当代码读取某个对象的某个属性时,都会执行一次搜索。首先搜索从对象实例本身开始。如果在实例对象本身找到了具有给定名字的属性,则返回该属性的值,如果没有找到,在继续搜索指针指向的原型对象

尽管可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反映出来,如果是重新写整个原型对象,那么情况就不一样了

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

 

5、原生对象模型
通过对原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新方法

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

 

6、原型对象的问题
首先,它省略了为构造函数传递参数这一环节,结果所有的实例在默认情况下都将取得相同的属性值。原型模式最大的问题是由共享的本性所导致的,对于包含基本值的属性可以再实例中添加一个同名属性而对于包含引用类型的属性来说,问题就比较突出了

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

而这个问题正是我们看到很少有人单独使用原型模式的原因所在

 

组合使用构造函数模式和原型模式


 

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

这是目前在ECMAScript中使用最广泛的一种创建自定义类型的方法,可以说,这是用来定义引用类型的一种默认模式

动态原型模式


把所有信息都封装在构造函数中,而通过在构造函数中初始化原型,又保持了同时使用构造函数和原型的优点

 

面向对象的程序设计-原型模式

 1     function Person(name,age,job){ 2         this.name = name; 3         this.age = age; 4         this.job = job; 5         if(typeof this.sayName != "function"){  //只有在初次调用构造函数时才会执行 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

面向对象的程序设计-原型模式

 

 寄生构造函数模式


 

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

   这个模式在特殊情况下来为对象创建构造函数,假设我们想创建一个具有额外方法的特殊数组

面向对象的程序设计-原型模式

 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

面向对象的程序设计-原型模式

 

稳妥构造函数模式


 所谓稳妥对象,值得是没有公共属性,而且其方法也不引用this对象

面向对象的程序设计-原型模式

 1    function Person(name,age,job){ 2  3        //创建要返回的对象 4        var o = new Object(); 5  6        //可以再这里定义私有变量和函数 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

面向对象的程序设计-原型模式

  这样,变量friend中保存着一个稳妥对象,而除了调用sayName()方法外,没有别的方式可以访问其数据成员。


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI