`
tulunta
  • 浏览: 378996 次
文章分类
社区版块
存档分类
最新评论

前端要给力之:原子,与原子联结的友类、友函数

 
阅读更多

JavaScript中的原子(Atom)是QoBean中提出的一个重要概念,借鉴自erlang,但具有与后者不同的含义。在QoBean里,Meta(元)与Atom(原子)是一对概念,前者表明执行系统中的最小单位,后者表明数据系统中的最小单位。QoBean约定这两个东西为一切元编程的初始,即最小化的执行系统与数据系统模型。

有什么意义呢?没什么意义。这只具备理论上的完整性。为了描述这种完整性,QoBean写了两个相当无厘头的函数:

好了。接下来的一切故事,从Atom开始,至于Meta(),我们今后再讲。

一、原子

====

Atom()函数只有一行代码,即:

atom是传入的参数。如果有该参数,则Atom()认为它是一个原子,返回之;如果没有,则创建一个空白对象作为原子,返回。

Atom()并没有检查atom参数的有效性,但在这里QoBean强制约定“atom参数必须是一个对象实例”。之所以使用强制约定,而不是参数类型检查,这与QoBean在元语言上的基本思想有关:仅从元语言角度,QoBean认为JavaScript只有对象和函数两种类型,且函数也是一种对象。所以,对于Atom()来说,以下三种情况是合法的:

当然有人会问:凭什么说一个函数从作为atom参数传入Atom(),再原封不动的传出来,就成了一个“原子”了呢?答案是:JavaScript固有的特性,任何两个对象既不相等(==),也不全等(===)。

也就是说,以JavaScript的固有性质来说,任何一个对象实例其实就是一个原子。即使任意两个空白的对象直接量,也是互不相等的。即:

当然,由于任何函数其实都是Function()的实例,所以也具有相同的性质:

二、原子的应用(1):识别器

====

在《JavaScript语言精髓与编程实践》中,谈到过对象的原子性的一种作用,亦即是作为“识别器”。例如说,我们知道硬币有正反两面,所以我们可以写这样的一个对象:

=========
x = {
front: true,
back: true
}
=========

显然我们可以用('front' in x)或者(x['front'])来识别它。但是这就存在了一个问题,因为x对象本来就有toString这样的属性,所以是不是说('toString' in x)为true,因此就表明x有一个名为'toString'的面了呢?同理,如果有人为x添加了一'middle'属性,那么将无法检查是x原本就有middle这个面呢,还是被某些代码污染了?

显然,按照对象设计的原理来说,将”属性”暴露出来,并可以任意读写,是导致这一切的根源。解决它的法子也很简单:用特定的方法来读取之。例如我们要查询"有没有某个面":

我们跨出了正确的一步。但是,与此前完全相同的原因,我们调用x.query('toString')时仍然返回true。这显然不是我们想要的,因为硬币显然没有'toString'这样的'面'。

好吧,我们再向前行一步。我们知道任何一个对象都具有原子性,也就是说唯一。我们只要创建一个对象,让他成为query所需要的一个“钥匙”;然后把这个钥匙藏起来,这样谁也找不到它,于是谁也不能干扰这个对象所约束的那些性质了。

实现起来也很简单:

好了,就这样。现在如果你调用coin.query('front')就一定返回true,而qoin.query('toString')则返回false了。

不过马上就会有人跳起来了:你这不是多此一举吗?既然sides已经是私有的了,就不必担心外面随意添加成员了呵!再则,不使用exist而使用类似true之类的值不也能判断吗?

是的,初看起来上述的置疑都对。不过在复杂的系统环境中,会存在三个问题,一个是sides[side]的效率不错,总比用数组实现来得强;第二个是,如果sides不在当前的函数内呢?第三个问题则更麻烦,如果你使用true之类的值,又如何避免第三方的代码通过Object.prototype来添加一个成员呢?

例如说,假定query()使用"sides[side] === true"来检测,的确可以避免toString之类的影响,但是如果有人写一行代码"Object.prototype.xxx = true",那coin.query('xxx')就将让人傻眼了。

所以,我们最好是找把钥匙藏起来,藏得好好的,别人都看不见。

三、原子的应用(2):友类与友函数

====

JavaScript没有明确的“类”的概念,所以这里讨论的友类与友函数其实是同一回事,只是Atom()作用于构造器还是普通函数的区别罢了。此外再强调一点,这里我们讨论的“友元”与“友函数”在名称上的确借鉴自C++,但概念上却有相当的差异。唯一与之相同的约定是,如果A是B的友函数,则A就能访问B的内部结构(例如私有成员)。

要实现这一点,我们得用Atom()把这两个函数联接起来。

举个例子来说,函数A内部有一个列表,记录了x,y,z三种状态。我们设定,有且只有函数B能修改之(当然A的一些内部的方法也能修改,但不是我们这里的主要问题),那么怎么办呢?

很自然的想法是让A公布一个方法出来。例如:

这样可以通过构建一个对象并用obj.set()来修改。或者我们将A整个的放在一个闭包里,再返回一个函数来做"修改state"的事情。但无论如何,我们只能做到“修改state",而无法做到“只有B能修改,其它位置都无法调用修改state的代码”。

好吧。传统观念上的、终极的方法, 是我们将state从A()里面移出来。然后将A()与B()放在同一个闭包里面:

问题是,在组织大型的代码、类库或类继承树时,我们可能无法保证A与B处于同一个函数,或者他们根本就不是一个人写的,或者B会是将来的开发人员追加编写的……等等如此,反正A不见得总能与B在一个函数上下文里。

解决这个问题的方法呢?使用Atom()来为A()与B()建立一个友元关系,使它们成为友函数(如果在对象继承中,则可以实现为友类)。如下:

现在,在最初的时候,A和B都指向一个原子。在得到“真实的A()、B()"的同时,函数A()、B()各持有了atom的一个引用。此后,系统中就再也找不到atom了——没有任何方法可以A、B之外再他们所使用的atom。

由于A()与B()各持有了一个atom,于是,当B()函数调用A(atom)时,A函数就绝对可以信任这是来自于B的调用,因此将state返回即可——当然也可以返回存取函数,或者别的什么东西。对于B()的调用A(atom),以及A()对arguments[0]进行的识别,一切都是安全的、不可能受外界其它任何因素影响的。

四、其它

====

1、同样的方法,我们可以对更多个的函数、构造器或子系统(使用同一个闭包上下文的大段代码块)建立友元关系。

2、原子性是JavaScript对象的固有特性,使用Atom()函数主要是可以上述技巧在系统中具有明确的语义,这比随处定义一个"{}"来得要好。

3、QoBean内部使用这一技术来构建类继承关系,从而使子类可以访问父类的特性,对非子类来说则完全隔离。

分享到:
评论

相关推荐

    Mysql知识点总结.pdf

    - 常用文本处理函数:如CONCAT()、LENGTH()、LEFT()、RIGHT()、UPPER()、LOWER()、SUBSTRING()等。 - 日期和时间处理函数:如NOW()、CURDATE()、DATE_FORMAT()、DATEDIFF()等。 - 数值处理函数:如ROUND()、RAND...

    离散数学期末复习笔记.doc

    本资源摘要信息是关于离散数学期末复习笔记的知识点总结,从命题逻辑、谓词逻辑、集合、关系与函数、图论等方面对离散数学的基本概念和理论进行了详细的介绍。 命题逻辑 命题逻辑是研究命题之间的逻辑关系的学科。...

    上海交通大学软件工程硕士-集合论与数理逻辑模拟题

    - **关系的性质**包括自反性(每个元素都与自己相关)、反自反性(没有元素与自己相关)、对称性(如果a与b相关,则b与a也相关)、反对称性(如果a与b相关且b与a相关,那么a=b)和传递性(如果a与b相关且b与c相关,...

    离散数学定义(必须背).doc

    当n=0时,这类函数被称为0元函数。 3. **命题合式公式** - 定义:命题合式公式可以通过以下规则构造: 1. 常元0和1是合式公式。 2. 命题变元本身也是一个合式公式。 3. 如果Q和R都是合式公式,那么(¬Q)、(Q∨R...

    数理逻辑之命题逻辑

    ### 数理逻辑之命题逻辑知识点详解 #### 一、数理逻辑概述 数理逻辑是逻辑学的一个分支,它利用数学方法研究思维规律。数理逻辑的特点在于它使用一套符号系统来简洁地表达各种推理的逻辑关系,因此也被称为符号...

    离散数学知识点(可编辑修改word版).docx

    - **原子公式**:不含任何逻辑联结词的最简单形式的公式。 - **合式公式**:符合语法规则形成的公式。 - **自由变元**:在公式中未被量词约束的变量。 - **约束变元**:被量词约束的变量。 - **辖域**:量词的作用...

    人工智能知识表示方法谓词逻辑70.pptx

    在命题逻辑中,表示单一意义的命题,称之为原子命题。原子命题通过“联结词”构成复合命题。五个联结词: ~表示“非”, ∧表示“合取”, ∨表示“析取”, 表示“蕴含”, 表示“等价”。 在命题逻辑中,...

    关系数据库模式规范化设计.pdf

    关系数据库模式规范化设计的基本概念包括关系模式、投影、自然联结、函数依赖、完全函数依赖、原子函数依赖、键和蕴含等。这些概念构成了关系数据库模式规范化设计的基础,了解这些概念对于理解和应用关系数据库模式...

    离散数学复习总结+试题

    复合命题则是通过联结词(如与、或、非)将原子命题组合起来形成。命题标识符和命题变元是表示命题的符号,原子变元则特指作为原子命题的命题变元。 2. **合式公式**:合式公式是按照特定规则构建的命题或谓词...

    OUC2022秋计科数据库系统重点

    * 函数依赖(FD):是指实体之间的函数关系 * 多值依赖(MVD):是指实体之间的多值关系 * 规范化:是指将关系数据库转换为标准形式 八、数据库设计 * 需求分析:是指收集和分析用户需求 * 概念结构设计:是指将...

    mysql大纲资料.txt

    高级SQL查询包括联结查询、子查询和聚合函数。联结查询允许从两个或多个表中查询数据,子查询是嵌套在其他SQL语句中的查询。聚合函数如COUNT、SUM、AVG、MAX和MIN可以对数据集合进行统计和计算。 数据库设计: ...

    西南交通大学数据库原理作业-第6章 关系数据库设计理论.docx

    第一范式(1NF)确保每个属性都是原子性的,第二范式(2NF)消除了非主属性对键的部分函数依赖,第三范式(3NF)进一步消除了非主属性对键的传递函数依赖。第四范式(4NF)处理多值依赖,第五范式(5NF,也称为项目...

    全国2007年7月高等教育自学考试离散数学试题

    - **联结词**:联结词的含义通过真值表确定,而不是自然语言的含义。 - **自由变元和约束变元**:在谓词逻辑中,自由变元和约束变元的区分是关键。 - **集合运算**:涉及到集合的补集、并集和交集运算。 离散...

    离散数学知识归纳.doc

    6. **合式公式**:与命题逻辑中的定义类似,但允许量词的存在,并有更复杂的构造规则。 7. **量词辖域**:量词所影响的公式部分,即它所限定的变量的有效范围。 8. **约束变元**:在量词辖域内出现的个体变元,其...

    数理逻辑基础

    复合命题则是由原子命题通过逻辑联结词(如“和”、“或”、“如果...则...”)构建而成的更复杂的命题,例如“如果今天下雨,则地面会湿”。在数理逻辑中,命题的一个重要特征是其真假性,即每个命题必须有确定的...

    离散数学知识汇总.pdf

    - **双条件联结词(IFF,↔)**:表示两个命题互为充要条件的关系。 2. **合式公式**: - **合式公式**的定义包括了所有合法的逻辑表达式结构,例如原子公式、否定、括号内的公式、合取、析取、条件和双条件联结...

    离散数学知识汇总.doc

    - 如果 R(x) 表示“x 是兔子”,T(x) 表示“x 是乌龟”,H(x, y) 表示“x 比 y 跑得快”,L(x, y) 表示“x 与 y 一样快”: - 兔子比乌龟跑得快表示为:∀x ∀y (R(x) ∧ T(y) → H(x, y))。 - 有的兔子比所有的...

    数据库原理复习题及答案A卷

    7. **自然联结**:两个关系进行自然联结时,需要它们之间有相同的属性,这些属性的值将用来匹配两个关系中的元组。 8. **DBA(数据库管理员)职责**:DBA 负责定义概念模式、修改模式结构、编写完整性规则,但不...

Global site tag (gtag.js) - Google Analytics