面向对象 - javascript创建对象模式总结
2013-05-04 20:22 MoltBoy 阅读(913) 评论(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... }; } }
动态原型模式相比较而言,可以说是比较完美的模式。但仍需注意的是,用在适合的地方才能能其发挥相应的优势。
总而言之,找到适合生产环境的模式才是最佳模式,至少目前没有任何一种模式能吃遍天下。