JavaScript面向对象程序设计(8): 优雅的封装仍是执行的效率?

优雅的封装仍是执行的效率?这是一个悖论。
 
优雅封装的程序看起来是那么的美妙:每一个属性被隐藏在对象以后,你所能看到的就是这个对象让你看到的,至于它究竟是怎么操做的,这个不须要你操心。
 
执行的效率就是另一回事。就像是C语言和面向对象的C++之间的差异:C++很优雅,可是执行效率,不管是编译后的二进制代码仍是运行期的内存的占用,都要比简单的C语言多出一截来。
 
这个问题在脚本语言中显得更加剧要,由于JavaScript根本就是一种解释语言,解释语言的执行效率要比编译语言低不少。
 
1. 优雅的封装
 
咱们先来看看变量封装。这里的变量不单单是属性,也包括函数。
 
前面已经说过,JavaScript中并无类这个概念,是咱们利用变量做用域和闭包“巧妙的模拟”出来的,这是一种优雅的实现。仍是温故一下之前的代码:
 
function Person() {
         var id;
         var showId = function() {
                alert( "My id is " + id);
        }
         this.getId = function() {
                 return id;
        }
         this.setId = function(newId) {
                id = newId;
        }
}
var p = new Person();
p.setId(1000);
alert(p.id); // undefined
// p.showId(); error: function not defined
var p2 = new Person();
alert(p.getId == p2.getId); // false
 
咱们很优雅的实现了私有变量——尽管是投机取巧的实现的。可是,这段代码又有什么问题呢?为何两个对象的函数是不一样的呢?
 
想一下,咱们使用变量的做用域模拟出私有变量,用闭包模拟出公有变量,那么,也就是说,实际上每一个建立的对象都会有一个相同的代码的拷贝!不单单是那个id,就连那些showId、getId 等函数也会建立屡次。注意,考虑到JavaScript函数就是对象,就不会感到那么奇怪了。可是毫无疑问,这是一种浪费:每一个变量所不一样的只是本身的数据域,函数代码都是相同的,由于咱们进行的是同一种操做。其余语言通常不会遇到这种问题,由于那些语言的函数和对象的概念是不一样的,像Java,每一个对象的方法其实指向了同一份代码的拷贝,而不是每一个对象都会有本身的代码拷贝。
 
2. 去看效率
 
那种封装虽然优雅,可是很浪费。好在JavaScript是一种灵活的语言,因而,咱们立刻想到,把这些函数的指针指向另外的一个函数不就能够了吗?
 
function show() {
        alert( "I'm a person.");
}
function Person() {
         this.show = show;
}
var p1 = new Person();
var p2 = new Person();
alert(p1.show == p2.show); // true
 
这个办法不错,解决了咱们之前的那个问题:不一样的对象共享了一份代码。可是这种实现虽然有了效率,但是却太不优雅了——若是我有不少类,那么岂不是有不少全局函数?
 
好在JavaScript中还有一个机制:prototype。还记得这个prototype吗?每一个对象都维护着一个prototype属性,这些对象的prototype属性是共享的。那么,咱们就能够把函数的定义放到prototype里面,因而,不一样的对象不就共享了一份代码拷贝吗?事实确实如此:
 
function Person() {
}
Person.prototype.show = function() {
        alert( "I'm a person.");
}
var p1 = new Person();
var p2 = new Person();
alert(p1.show == p2.show); // true
 
不过,这种分开定义看上去很别扭,那么好,为何不把函数定义也写到类定义里面呢?
 
function Person() {        
        Person.prototype.show = function() {        
                alert( "I'm a person.");        
        }        
}        
var p1 = new Person();        
var p2 = new Person();        
alert(p1.show == p2.show); // true
 
实际上这种写法和上面一种没有什么不一样:惟一的区别就是代码位置不一样。这只是一个“看上去很甜”的语法糖,并无实质性差异。
 
最初,微软的.Net AJAX框架使用前面的机制模拟了私有变量和函数,这种写法和C#很相像,十分的优雅。可是,处于效率的缘故,微软后来把它改为了这种原型的定义方式。虽然这种方式不那么优雅,可是颇有效率。
 
在JavaScript中,这种封装的优雅和执行的效率之间的矛盾一直存在。如今咱们最好的解决方案就是把数据定义在类里面,函数定义在类的prototype属性里面。
相关文章
相关标签/搜索