JavaScript之常见设计模式(2)(面向对象的程序设计)

来源:互联网 发布:饼干网络意思 编辑:程序博客网 时间:2024/05/20 20:01

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

在上述例子中,包含引用类型的原型模式,当修改一个实例的属性值时,其它实例的这个属性值也会相应变化。以及实例要有属于自己的属性这两个问题没有得到解决。
解决以上两个问题的方法:我们可以将 实例本身的属性构造函数封装起来,而 将共享的属性和方法原型对象封装起来。

创建自定义类型最常见的方法,就是组合使用构造函数模式和原型模式。构造函数模式用于定义实例自身的属性原型模式用于定义实例共享的属性和方法最后每个实例都有一个自己的实例属性副本,又有共享的属性和方法。 这种自定义类型方法是一种默认的方法。

将前面的代码重写:
//定义一个构造函数,用于定义实例本身的属性(实例的副本)function Person (nama, age, job) {    this.name = name;    this.age = age;    this.job = job;    this.colors = ["red", "blue", "yellow"]; //数组}//在原型对象中定义共享的属性和方法Person.prototype = {    constructor : Person,    sayName : functionn () {        alert(this.name);    }};//定义实例对象var person1 = new Person("Tom", 20, "WEB前端"); //在创建实例时,对实例进行了初始化。var person2 = new Person("Bob", 30, "Doctor"); //在创建实例时,对实例进行了初始化操作。console.log(person1.color); //["red", "blue", "yellow"] 在没有给person1的color属性添加新值之前console.log(person2.color); //["red", "blue", "yellow"]person1.color.push("orange"); //为person1的color添加新值(栈方法)console.log(person1.color); //["red", "blue", "yellow", "orange"]console.log(person2.color); //["red", "blue", "yellow"] person2的属性没有变化console.log(person1.color === person2.color); //false 这两个实例的属性自然不全等console.log(person1.sayName() == person2.sayName()); //true 方法是共享的,所以是相等的console.log(person1.sayName()); //Tomconsole.log(person2.sayName()); //Bob

实例本身的属性是由构造函数定义的,构造函数提供实例单独属性的副本,而所有共享属性constructor和共享方法sayName()是由原型对象定义的,原型对象提供共享的方法和属性。

当修改了person1.color的值时,相当于是在person1的实例副本中修改的,不会由指针传向原型对象中,不会影响到person2.color,因为它们引用一不同的数组。person1和person2实例本身的属性是相互独立的。这种由构造函数模式与原型模式组合的方式,是一种认知度很高的自定义类型的方法。可以说是定义引用类型的默认方式。


动态原型模式

动态原型模式所有的信息 封闭 在构造函数中通过构造函数来初始化原型。它是通过检查某个应该存在的方法 是否有效,来确定是否初始化原型。

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);        };    }}var person1 = new Person("Jon", 25, "QC"); //创建实例并初始化。person1.sayName(); //Jon


初始化部分,只有在sayName()方法不存在的情况下,才将它添加到原型中。这段代码只会在初次调用构造函数时才会执行,此后,原型已完成初始化。之后就不会作修改了,原型对象中的修改,会即时在所有实例中得到反应。这个方法很完美。
if语句检查的可以是 初始化之后 应该存在 的属性和方法。不用对每个属性和方法进行检查,检查一个就行。

用该模式创建的对象,可以用instanceOf()检查其属于什么引用类型。


使用动态原型的情况下,不能用对象字面量法重写原型,在已经定义了实例的情况下重写原型,会断掉实例与原型的联系。


稳妥构造函数模式


稳妥对象,指的是既 没有公共属性,而且其方法也不用this的对象,也不用new关键字创建实例。

特点:一是 创建的实例对象的实例方法不用this,二是 定义实例对象不使用new操作符。

function Person (name, agem, job) {    //创建要返回的对象    var o = new Object();    //添加私有方法和属性        //添加方法    o.sayName = function () {        alert(name); //新创建的对象的实例方法不用this    };    return o; //返回对象}var person1 = Person("Cray", 18, "student"); //没有用new操作符定义实例对象person1.sayName();// Cray

person中保存的是一个稳妥对象,除了调用sayName()方法外,没有其它方式访问其数据成员,即使有其它代码给这个对象添加属性和方法,但也没有方法访问传入到构造函数中的原始数据。
缺点:返回的对象o与构造函数和构造函数的原型属性没有任何关系,与在外部创建的对象没什么区别,因此,不能依赖用instanceof来确定其实例的类型。

寄生构造函数模式

寄生构造函数模式可以看作是构造函数模式与工厂模式的结合,建议在使用其它模式时,不用使用寄生构造函数模式。
//构造模式与工厂模式的结合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 person = new Person("Tom", 21, "web前端"); console.log(person.name); //Tomconsole.log(person instanceof(Person)); //falseconsole.log(person instanceof(Object)); //true

与构造函数模式相似点:函数名首字母大写、实例用new创建。
与工厂模式相似点:有初始化参数、在内部创建一个对象、返回这个对象、创建实例时可以初始化实例。

缺点:返回的对象o与构造函数和构造函数的原型属性没有任何关系,与在外部创建的对象没什么区别,因此,不能依赖用instanceof来确定其实例的类型。


0 0
原创粉丝点击