JavaScript之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)

一、动态原型模式

在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此!

有其他oo语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑。因为对象在其他oo语言中往往是封装在一块的,而构造函数确是和原型分开的,所以并没有真正意义上的封装,所以动态原型模式正是致力与解决这一问题的一个方案!

动态原型模式将所有的信息都封装在构造函数中(包括原型和实例属性),通过在构造函数中实例化原型(仅在必要的情况下)实现封装,又保持了同时使用构造函数和原型的优点。

    function Person(name,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.friends=["小超","大超"];
        if(typeof this.sayName!="function") {//这段判断语句的作用是限制Person.prototype属性(原型属性对象)只生成一次,要不然每次实例化一个Person对象都会去写一遍原型对象
            Person.prototype.sayName = function () {
                alert(this.name);
            }
            Person.prototype.sayHello=function(){
                alert("Hello");
            }
        }
    }
    var person=new Person("张三",22,"coder");
    person.sayName();

注意:typeof this.sayName!="function" 中的this,因为创建Person构造函数时,会创建一个prototype属性,该属性实际上就是Person.prototype的原型对象,prototype属性是一个指针,指向Person.prototype的原型对象,所以构造函数拥有所有Person.prototype的原型对象的属性和方法,而创建Person.prototype圆形对象时,会生成一个constructor属性,该属性也是一个指针,指向Person构造函数,用于判断对象实例的类型!

因为Person构造函数够拥有Person.prototype的原型对象的所有属性和方法,所以可以用this判断原型中是否存在该方法!

 

当第一次实例化Person对象的时候,原型就已经完成初始化,所以当第二次实例化的时候,原型就不会初始化,而且if语句检查的可以是原型的任意属性和方法,不需要每一个都检查,只需要检查其中一个,对于采用这种模式创建的自定义类型,可以同时使用constructor和instanceof来检查他们的类型,代码如下:

    function Person(name,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.friends=["小超","大超"];
        if(typeof this.sayName!="function") {     //这段判断语句的作用是限制Person.prototype属性(原型属性对象)只生成一次,要不然每次实例化一个Person对象都会去写一遍原型对象
            Person.prototype.sayName = function () {
                alert(this.name);
            }
            Person.prototype.sayHello=function(){
                alert("Hello");
            }
        }
    }
    var person=new Person("张三",22,"coder");
    var person1=new Person("李四",22,"coder");
    alert(person.constructor);   //输出:   Person构造函数所对应的方法体
    alert(person instanceof Person);   //输出:true  说明person是Person对象的实例
    alert(person.constructor==person1.constructor); //输出:true   说明两个实例的原型对象的constructor属性都指向Person构造函数即他们是同一类型

 

 

二、寄生构造函数模式

 当你需要创建一个自定义类型的时候,当前面的随笔中的模式都不适用的情况下,可以使用寄生构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码。

代码如下:

//寄生构造函数模式
function Person(age,name) {
    var o=new Object();
    o.age=age;
    o.name=name;
    o.sayName=function(){
        alert(this.name);
    }
    return o;
}
var person=new Person(22,"张三");
    person.sayName();

//工厂模式
    function createPeron(name,age,job){
        var object=new Object();
        object.name=name;
        object.age=age;
        object.job=job;
        object.sayName=function(){
            alert(this.name);
        }
        object.sayForm=function(){
            alert(typeof this);
        }
        return object;
    }
    var person=createPeron("张三",22,"coder");
    person.sayName();
    person.sayForm();

在上面寄生模式的例子中,Person函数创建了一个新对象,并以相应的属性和方法初始化该对象,然后又返回这个对象。

然后分析其与工厂模式的区别:

1、寄生模式创建对象时使用了New关键字

2、寄生模式的外部包装函数是一个构造函数

除了上面这2个区别寄生模式和工厂模式几乎一样,构造函数在不返回值的情况下,默认返回对象的新实例。而通过在构造函数的末尾添加一个return 语句,可以重写调用构造函数是返回的值

 

作用:寄生模式可以在特殊的情况下为对象来创建构造函数,原因在于我们可以通过构造函数重写对象的值,并通过return返回  重写调用构造函数(创建的对象的实例)之后的对象实例的新的值。

假设我们想创建一个具有额外方法的特殊数组。由于不能直接修改Array构造函数,所以我们可以使用寄生模式。代码如下:

function SpecialArray() {
    //创建数组
    var array=new Array();
    //添加值  arguments获取的是实参,不是形参,所以SpecialArray()并没有形参接收传递过来的参数
    array.push.apply(array,arguments);
    array.toPipedString=function(){
        return this.join("|");
    }
    return array;
}
var colors=new SpecialArray("red","blue","black");
alert(colors.toPipedString());  //输出:red|blue|black

我们利用寄生构造函数模式,在不修改Array构造函数的情况下,通过为Array对象创建构造函数达到修改Array对象的目地;

在分析上面的代码:

1、var array=new Array();创建了一个Array对象

2、return array;在经过一系列的修改之后返回修改之后的Array对象

3、var colors=new SpecialArray("red","blue","black"); 创建了一个SpecialArray对象,接收的确是修改之后的Array对象的实例值

所以return array;返回的对象是Array类型,而且colors接收了这个返回的对象,所以colors并不是SpecialArray构造函数的实例,而是Array的实例,下面的代码可以说明:

alert(colors instanceof SpecialArray); //输出:false
alert(colors instanceof Array); //输出:true

所以,由于存在上述问题,如果能使用其他的模式的情况下,建议不要使用这种模式.

 

三、稳妥构造函数模式

道格拉斯 *  克罗克福德 发明了JavaScript中的稳妥对象这个概念.所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象最适合用在一些安全的环境中(这些环境会禁止使用new和this),或者防止数据被其他的应用改动。

稳妥构造函数与寄生构造函数模式类似,但是也有两点区别:

1、稳妥模式不使用new操作符调用构造函数

2、新创建对象的实例方法不引用this

其代码如下:

function Person(name,age) {
    //创建要返回的对象
    var o=new Object();
    //可以在这里定义私有变量和函数
    //添加方法
    o.sayName=function(){
        alert(name);
    }
    //返回对象
    return o;
}
var person=Person("张三",22);
    person.sayName();  //使用稳妥构造函数模式只能通过其构造函数内部的方法来获取里面的属性值

上面的代码定义了一个person变量,里面保存的是一个稳妥对象,而除了吊用他的sayName()方法外,没有别的方法可以访问其数据成员。即使有其他的代码会给这个对象添加方法和数据成员,但也不可能有别的方法访问到传入到构造函数中的原始数据。稳妥构造函数模式提供的这种安全性。是的它非常适合在某些安全执行环境中。

 

posted @ 2016-09-07 11:33  郑小超  阅读(1474)  评论(0编辑  收藏  举报