`
Finder
  • 浏览: 26728 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

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属性里面。

分享到:
评论
43 楼 sankooc 2010-01-05  
小问一下js里等号比较的是什么 值 还是?
42 楼 jessige_27 2010-01-04  
zzhonghe 写道
jessige_27 写道


但是 差别是有的 运行这个试试
var p1 = new Person();
var show = p1.show;
var p2 = new Person();
alert(show == p2.show); // false




楼上有没有跑一下啊, 这个怎么执行都是true.

关于优雅的问题,实在是没有规定说写成POJO那样就算优雅,关键还是在于习惯。prototype的方式,既好理解,又能方便重用,更易于扩展,是在没理由说它不优雅。


当然跑过 我发的帖子是针对楼主所说的
引用
实际上这种写法和上面一种没有什么不同:唯一的区别就是代码位置不同。这只是一个“看上去很甜”的语法糖,并没有实质性差别。

上面的那段代码 我没把所有的代码都帖上来
你是用正常的prototype方式定义的Person吧 那正好说明了楼主这种的方式有问题
运行下面的试试 这个就是false了
function Person() {
  Person.prototype.show = function() {
    alert("I'm a person.");
  }
}

var p1 = new Person();
var p1_show = p1.show;

var p2 = new Person();
alert(p1_show == p2.show); // false

alert(p1.show == p2.show); // true
41 楼 冯冀川 2009-11-04  
我觉得讨论这些问题的初衷,还是由于现在大量的js程序员是由java,php,c#程序员转过来的,或者说是有服务器端语言为基础,然后向前端衍生,前后台的代码都写,所以希望js能够模拟出某种语言的特性出来。
如果一个从最初就是从事于js代码编写的程序员,我想对该采取那种方式也就不会太在意了,因为js有他自己的方式
40 楼 zzhonghe 2009-11-01  
jessige_27 写道


但是 差别是有的 运行这个试试
var p1 = new Person();
var show = p1.show;
var p2 = new Person();
alert(show == p2.show); // false




楼上有没有跑一下啊, 这个怎么执行都是true.

关于优雅的问题,实在是没有规定说写成POJO那样就算优雅,关键还是在于习惯。prototype的方式,既好理解,又能方便重用,更易于扩展,是在没理由说它不优雅。
39 楼 jessige_27 2009-10-31  
引用
实际上这种写法和上面一种没有什么不同:唯一的区别就是代码位置不同。这只是一个“看上去很甜”的语法糖,并没有实质性差别。

这是错的
var p1 = new Person();
var p2 = new Person();
alert(p1.show == p2.show); // true

这么写确实得到的是true

但是 差别是有的 运行这个试试
var p1 = new Person();
var show = p1.show;
var p2 = new Person();
alert(show == p2.show); // false

注意别改变第二三行的顺序

原因是在new p2的时候 把prototype的show换掉了
而p1.show和p2.show实际上都是prototype.show 相等是当然的

引用
“看上去很甜”的语法糖
那里面不知道是什么东西
38 楼 vieri122 2009-09-17  
继续期待楼主的好文章
37 楼 shewa5337 2009-08-14  
看完了,应该说是扫了一遍,回去啃js设计模式,看起来挺好的一本书。
36 楼 roadray 2009-07-15  
jamiesun 写道
java中的getXXX,setXXX都令人快吐了,js还要搞这一套?


var person = new Object()
person.name = 'xxxx'
person.sex = 'y'

.............


我只喜欢这么搞。


我那个代码意在表示类属性写在function里,而方法写在prototype里,怪我例子写的不明显导致感觉是在模拟pojo
35 楼 jeff312 2009-07-14  
不过有点不太理解LZ的意思,prototype怎么就“不优雅”了呢?男人跟女人不一样,所以嘴上会多一小撮胡子;女人跟男人不一样,所以胸前会多两块肥肉……可是男人女人都很优雅啊。
34 楼 night_stalker 2009-07-14  
架构的作用就是把庞大的代码划分成相对独立的小块,小块只要满足要求,里面随便怎么搞都没问题。(不过我觉得数 M 的 javascript 就够扯蛋的了)

维护问题是 java 固有的,java 程序很啰嗦,导致很难维护,所以程序员都神经兮兮,无论写什么都在想维护的事情 ……
33 楼 jeff312 2009-07-14  
robinqu 写道
JavaScript权威指南 有写过模拟Class继承的例子,静态变量、局部变量、公有变量等等都可以模拟~
当时我读完了那一章就觉得累,何必去模拟自己无法做到的东西

所以用prototype继承才是Js的王道吧~要不然就有点东施效颦的感觉了~

说句非常不负责任的话,如果不是做稍微大一点的项目,也就50行左右的代码,你还管这么多么?肯定是非常面向过程的代码吧……汗
再大一点的东西,肯定会基于类库,jQuery之类……


类库是帮你少写点效果实现,它不能帮你解决商业逻辑问题,现在有不少系统(包括某些银行系统)都用javascript写整个前端,数M甚至数十M的代码量,这能靠类库堆积起来?不用面向对象设计,将来维护起来够你受的。
32 楼 jeff312 2009-07-13  
incredible 写道
本来就是不面向对象的东西


这你就错了,js全身上下都是对象,函数本身也是对象。之所以没法按照Java那样写闭包,仅仅是因为它是逐行解释的脚本语言,没法像静态编译语言那样重用字节码。
31 楼 墓里活人 2009-07-13  
jamiesun 写道
java中的getXXX,setXXX都令人快吐了,js还要搞这一套?


var person = new Object()
person.name = 'xxxx'
person.sex = 'y'

.............


我只喜欢这么搞。



还是太啰嗦了,要这么搞:
  
   var person = {};
   obj.name = "xxx";
   obj.sex = "yyy";
   obj.myFunction = function(){ alter(obj.name);  }

   var ePer = {};
   ePer ['field'] = 'field';
   ePer.myFunction  = function(){ alter(ePer .'field')  };
    //继承 - (重载)
   ePer.extendBy = function(parant){
          for(var i in person ){
            if(parant[i]=="undefine")continue;
            extendPer[i] =  parant[i];
         }
   }
   //进行继承 或重载。呵呵
   ePer.extendBy(person);
   
  
30 楼 jamiesun 2009-07-13  
java中的getXXX,setXXX都令人快吐了,js还要搞这一套?


var person = new Object()
person.name = 'xxxx'
person.sex = 'y'

.............


我只喜欢这么搞。

29 楼 robinqu 2009-07-13  
JavaScript权威指南 有写过模拟Class继承的例子,静态变量、局部变量、公有变量等等都可以模拟~
当时我读完了那一章就觉得累,何必去模拟自己无法做到的东西

所以用prototype继承才是Js的王道吧~要不然就有点东施效颦的感觉了~

说句非常不负责任的话,如果不是做稍微大一点的项目,也就50行左右的代码,你还管这么多么?肯定是非常面向过程的代码吧……汗
再大一点的东西,肯定会基于类库,jQuery之类……
28 楼 roadray 2009-07-12  
ranLoD 写道
roadray 写道
有没有人用这种?够不够优雅
var Person = function(){
   this.name = null;
   this.sex = null;
}

Person.prototype = {
  getName:function(){
    return this.name;
  },
  
  getSex:function(){
    return this.sex;
  }



}


这么烂的你也好意思贴出来,都被js书用烂了的例子

神仙你从哪飞来,吃了火药了,一上来就喷人,你NB,自己写个模式出来看看
这模式在YUI中大量应用,你的意思是YUI的代码页烂了哦
27 楼 black.angel 2009-07-08  
js 这东西,如果写成公用的API的确用类式继承比原型继承容易阅读和理解,不过效率就会慢很多。。。。。
26 楼 kjj 2009-07-03  
强扭的瓜不甜,本来没有oo特性的东西,真不知道价值在那里!
25 楼 pipilu 2009-07-03  
zhbh27 写道
我看了一书中有写到:“闭包”这种间接保持变量值的机制,往往会给JavaSript的垃圾回收器制造难题。特别是遇到对象间复杂的循环引用时,垃圾回收的判断逻辑非常复杂。无独有偶,IE浏览器早期版本确实存在JavaSript垃圾回收方面的内存泄漏问题。再加上“闭包”模型在性能测试方面的表现不佳,微软最终放弃了“闭包”模型,而改用“原型”模型,即prototype。


希望有人能证实一下这种说法的可靠性。
如果写javascript不用闭包我都不知道该怎么写。
24 楼 wkbulletin 2009-07-03  
脚步语言就自己的规则,为什么要把面向对象的规则强加给他呢

相关推荐

    JavaScript面向对象程序设计

    JavaScript面向对象程序设计(1): 前言 JavaScript面向对象程序设计(2): 数组 JavaScript面向对象程序设计(3): 对象 JavaScript面向对象程序设计(4): 函数...JavaScript面向对象程序设计(8): 优雅的封装还是执行的效率?

    JavaScript程序设计课件:面向对象概述.pptx

    JavaScript程序设计 面向过程与面向对象 6.1.1 面向过程与面向对象 1、概念 面向过程(Procedure Oriented)也可称之为“面向记录”,是一种以过程为中心的编程思想。它注重的是具体的步骤,只有按照步骤一步一步...

    javascript 面向对象编程基础:封装

    但是(这里本人要苦大仇深、痛心疾首地说),“而Ajax的出现使得复杂脚本成为必需的组成部分,这就对 JavaScript 程序设计提出了新的要求,很多Ajax应用开始利用JavaScript面向对象的性质进行开发,使逻辑更加清晰。...

    javascript面向对象三大特征之封装实例详解

    主要介绍了javascript面向对象三大特征之封装,简单描述了封装的基本概念、原理,并结合实例形式详细分析了javascript面向对象程序设计中封装的用法与相关操作注意事项,需要的朋友可以参考下

    Javascript 面向对象编程(一) 封装

    学习Javascript,最难的地方...《Javascript高级程序设计(第二版)》(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Javascript读物,推荐阅读。 笔记分成三部分。今天的第一部分是讨

    javascript 面向对象全新理练之数据的封装

    它是面向对象程序设计的三要素之首,其它两个是继承和多态,关于它们的内容在后面再讨论。 关于数据封装的实现,在 C++、Java、C# 等语言中是通过 public、private、static 等关键字实现的。在 JavaScript 则采用了...

    写给大家看的面向对象编程书(第3版).[美]Matt Weisfeld(带详细书签).pdf

    本书是一部独具特色的面向对象技术著作。书中结合代码示例生动透彻地讲述了面向对象思想的精髓,让读者真正学会以对象方式进行思考。此外,本书还讨论了各种与面向对象概念密切相关的应用主题,包括XML、UML建模语言...

    Javascript OOP之面向对象

    面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和...

    JavaScript的面向对象编程基础

    为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对象中的几个概念: 一切事物皆对象 对象具有封装和继承特性 对象与对象之间使用消息通信,各自存在信息隐藏 以...

    Javascript简单实现面向对象编程继承实例代码

    本文讲述了Javascript简单实现面向对象编程继承实例代码。分享给大家供大家参考,具体如下: 面向对象的语言必须具备四个基本特征: 1.封装能力(即允许将基本数据类型的变量或函数放到一个类里,形成类的成员或方法) ...

    javascript 面向对象全新理练之继承与多态

    前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员、公有实例成员、私有静态成员、公有静态成员和静态类的封装。这次我们来讨论一下面向对象程序设计中的另外两个要素:继承与多态。

    Object-oriented-programming-for-JavaScript-developers:适用于JavaScript开发人员的面向对象编程的代码存储库

    熟悉JavaScript语言构造的基础知识以及面向对象的编程及其应用程序。 学习使用Node.js在JavaScript中构建可扩展的服务器应用程序 以三种编程语言生成实例:Python,JavaScript和C# 结合使用访问修饰符,前缀,...

    详解JavaScript对象和数组

    许多高级编程语言都是面向对象的,比如C++、C#和Java等高级程序设计语言,那么一种面向对象语言有哪些基本要求呢?下面我们就通宿地说一下面向对象的一些知识。 一种面向对象语言需要向开发者提供四种基本能力: (1...

    JavaScript王者归来part.1 总数2

     1.5 安全性和执行效率   1.6 一个例子--JavaScript编写的计算器   1.7 学习和使用JavaScript的几点建议   1.8 关于本书的其余部分   第2章 浏览器中的JavaScript  2.1 嵌入网页的可执行内容   2.2 ...

    JavaScript使用prototype原型实现的封装继承多态示例

    主要介绍了JavaScript使用prototype原型实现的封装继承多态,涉及javascript prototype与面向对象程序设计相关操作技巧,需要的朋友可以参考下

    算法实践(JavaScript & Java),排序,查找、树、两指针、动态规划等.zip

    面向对象: Java是一种纯粹的面向对象编程语言,支持封装、继承和多态等面向对象的概念。这使得Java编写的代码更加模块化、可维护和可扩展。 多线程支持: Java内置了对多线程的支持,允许程序同时执行多个任务。这...

    programming_fundamentals_003:使用面向对象原理重新设计书店

    我们将重新访问目录服务,除了这次我们将以面向对象的思维方式来进行程序的设计。 这意味着将“书籍”视为具有封装数据和行为的对象。 技术 我们将继续在环境中使用Javascript编程语言,并利用称为的测试框架来运行...

    event.js:基于事件的同步执行方法

    昨天看书在看面向对象程序设计章节时又看到其中一个叫模块模式,于是自己心血来潮想依着require的API自己实现一个模块加载器,略复杂,其中卡在加载各个依赖关系上面卡了一会,每个require或define如果有依赖项就得...

Global site tag (gtag.js) - Google Analytics