代码改变世界

面向对象 - javascript创建对象模式总结

2013-05-04 20:22  MoltBoy  阅读(907)  评论(3编辑  收藏  举报

  面向对象(Object-oriented,OO)是如今主流的编程模式,而面向对象又分为(OOA-面向对象分析、OOD-面向对象设计、OOP-面向对象编程),我们常常挂在嘴边都是OOP。通常,面向对象都有类得概念,javascript中没有涉及到类得概念,却有对象的概念。在ECMA-262中把对象定义为:“无序属性的集合,属性值可以为基本值、对象或函数”。实际上,对象可以理解为散列表,就是一组租名值对,其中值可以为数据或者函数。

  了解了对象的概念,下一步当然是创建对象。在平日里讨论,经常能听到:“工厂模式”、“组合模式”...等一些关于创建对象的术语。下面的内容就具体讨论各模式的特点及其优缺点。

  工厂模式

  工厂模式不止在javascript里被人熟知,在整个软件工程领域内都广为人知。

function Fn() {
    var obj = {};
    obj.value = 'molt';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}

  上诉案例为典型的工厂模式,函数内定义一个新对象,利用新对象方法访问函数私有属性,最后返回新对象。这种设计模式优缺点非常明显,优点创建简单,易于理解。但是也随之带来了非常不好的地方:

  ①、内存占用高,因为实例不能共享原型上的方法,甚至原型在此模式下颇为尴尬;

  ②、实现继承不方便,需要copy对象的所有属性,或者把对象作为新建对象的原型。

  构造函数模式

function Fn(name, age){
    this.name = name;
    this.age = age;
    this.method = function(){
        //coding...
    }
}

   构造函数模式没有return语句,也没有创建新的对象,并且函数名按照惯例需要大写字母开头。此模式相对比较常见,因为跟其他面向对象语言的方式比较接近,更易于理解。但是它页同样存在着不能共享原型方法的缺点,每个实例对象都需要单独clone方法,从性能角度来说,这样做颇为浪费!

  原型模式

  javascript是基于原型的编程语言,每个函数都有一个prototype原型属性,这个属性其实也是个对象,主要用来储存实例共享的属性和方法。

function fn(){}
fn.prototype = {
  constructor: fn, name: “tom”, sayName:
function(){ console.log(this.name); } };

  此模式下,的确共享了属性和方法,每个实例无需再单独clone原型中的属性和方法,实际上是创建实例之时,浏览器会自动创建一个内部属性指向构造函数的原型。在FF中,这个内部属性实现为:__proto__,但并非所有浏览器都实现了这个属性。为了便于理解原型和构造函数以及实例之间的关系,下面的图形有助于你的理解。

  原型也并非无缺点,那就是创建的实例属性都是一样的,并且属性若是引用类型,实例之间的修改将会相互影响。若要避免这种问题的出现,可以结合原型和构造函数模式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。得到的结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用。

  构造函数和原型的组合模型

function fn(name, age){
    this.name = name;
    this.age = age;
}
fn.prototype = {
    constructor: fn,
    sayName: function(){
          console.log(this.name);  
    }    
};

  目前这种混合模式使用最为广泛,认可度也是最高的。

  动态原型模式

  动态原型模式将所有的信息都封装在构造函数中,而通过在构造函数中初始化原型,同时保持着构造函数和原型的优势。

function fn(name, age){
    this.name = name;
    this.age = age;
    if(typeof this.sayName != "function"){
        fn.prototype.sayName = function(){  //使用对象字面量重写会覆盖这个原型
            //coding...
        };
    }
}

  动态原型模式相比较而言,可以说是比较完美的模式。但仍需注意的是,用在适合的地方才能能其发挥相应的优势。

  总而言之,找到适合生产环境的模式才是最佳模式,至少目前没有任何一种模式能吃遍天下。