Press "Enter" to skip to content

javascript创建对象的常用模式

本文介绍了javascript中创建对象常用的几种模式,包括:工厂模式,构造函数模式,原型模式,组合构造函数与原型的模式,动态原型模式。
一.工厂模式
看如下代码:

function getMySon(name,sex){
    var o={};
    o.name=name;
    o.sex=sex;
    o.sayName = function(){
        alert(this.name);
    }
    return o;
}
son1 = getMySon('li ming','male');
son2 = getMySon('li hong','female');

这就是工厂模式。在函数中定义一个对象,并为其添加属性与方法,最后将这个对象返回。虽然这种模式实现了方便的创建对象,但是有这样一个问题,即不能判断这个实例到底是谁创建的。
比如 son1 intanceof getMySon并不能返回 true。因为这里的实例确切来说并不是由getMySon 通过new来创建的,而是getMySon中的 o。
所以工厂模式并不适合需要创建很多种对象的情况。
那么怎么创建对象才能正确的判断实例是从哪儿来的呢?下面就要说到构造函数模式了。
二.构造函数模式
看如下代码 :

function getMySon(name,sex){
    this.name = name;
    this.sex = sex;
    this.sayName = function(){
        alert(this.name);
    }
}
son1 = new getMySon('li ming','female');

这就是构造函数模式,注意在调用时要用 new。
在进行new调用时,进行如下几个步骤:

            1. 创建一个新的对象(并把空对象的__proto__属性设置为getMySon.prototype)。
            2.将构造函数的作用域赋给新对象(此时this 指向了这个新对象)。
            3.执行构造函数中的代码(通过this 为这个新对象添加属性)
            4.返回新对象。

通过这种方式产生的实例可以使用son1 instanceof getMySon来判断实例是由谁来产生的。
那么使用构造函数有什么问题呢?由于每次使用new时都会创建一个新的对象,那么所有的数据在不同实例之间是不共享的。但是对于函数sayName来说,它并没有必要创建多个。这样做浪费了空间。
这样就引出了下一种,原型模式。
三. 原型模式
看如下代码:

function getMySon(){}
getMySon.prototype.name = 'li ming';
getMySon.prototype.sex = 'female';
getMySon.prototype.sayName = function(){
    alert(this.name);
};

这就是原型模式(原型的相关知识这里不详细说)。
原型模式将属性和方法添加到了getMySon.prototype里,prototype由所有的实例共享,它只有一份,并不是所有的实例各有一份。
这种方式实现了让函数只有一份,不必占用多余的空间。但是,name,sex之类的属性并不需要在所有实例间共享,而且使用原型模式进行传参生成这些属性也不方便。
那么可以合并构造函数模式与原型模式,利用它们各自的优点。让各实例间不需要进行共享且需要通过传参进行生成的属性放在构造函数模式中生成,让各实例中需要共享的(比如方法)在原型模式中生成。
三. 组合构造函数与原型的模式
看如下代码:

function getMySon(name,sex){
    this.name=name;
    this.sex=sex;
}
getMySon.prototype.sayName(){
    alert(this.name);
}
son1=new getMySon('li ming','female');

这是 组合构造函数与原型的模式 。这种方式结合了构造函数模式与原型模式的优点。这是最常用的一种创建对象的模式。
四. 动态原型模式
所谓动态原型模式,其实是对 组合构造函数与原型的模式 的一种封装。
看如下代码:

function getMySon(name,sex){
    this.name = name;
    this.sex = sex;
    //即使有多个需要定义的方法,也只需判断一个方法。
    if(typeof sayName != 'function'){
        getMySon.prototype.sayName=function(){
            alert(this.name);
        }
    }
}
son1=new getMySon('li ming','female');

这里之所以命名为动态原型模式,是因为getMySon在不同的调用中会发生变化,是动态的。只有在第一次调用getMySon时才会执行对sayName函数的定义。
从本质来看,仍然是将不需共享的通过构造函数进行定义,需要共享的方法通过原型进行定义。只是将它们放在了一起,进行了封装。

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax