`
hax
  • 浏览: 962829 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Module与Trait的比较

    博客分类:
  • JS
阅读更多
最近我多次提及module和trait。

粗看,我们可以发现它们有一定的相似处。两者其实都是为了组织代码单元,并在代码上施加更多的约束,且约束的方式有点类似。

目前典型的module是定义require和exports,即需要哪些包(所提供的类和函数),和输出哪些类和函数。

而trait是定义一组方法,并声明这些方法所依赖的方法(即require某些方法)。比如 IterationTrait 可定义 map, filter, reduce, reduceRight 等方法,并声明需要 forEach 方法。这也意味着前些方法内部可能是由forEach方法实现的。


如果看过Ruby语言的设计,就可以理解module和trait的相似性。组合一个trait,就相当于引入一个module。不过我个人并不赞同这样的设计,因为这种相似性只是结构上的。

从概念上说,module和trait两者的共通处是都要强制明确所有的耦合点。区别在于,trait的目的是提供类实现的组合和复用机制,因此其更强制内聚性。module则不带有这个目的。


通常,在module中用到的和输出的函数,都应该是无副作用的(不引起外界可观察到的状态变化)。类,也可视为一种无副作用的函数,因为状态变化被封装到类所产生的对象实例中了,而对象实例是跨模块隔绝的(即对于不同module中创建的对象实例,它们的方法调用只影响它们各自的状态,而不会互相影响)。反过来,要让会引起状态变化的函数也跨模块隔绝相当困难(这意味着被调用函数必须知道它在哪个模块中被调用,这样才能为不同模块保存互相独立的状态)。

这方面的反例是单例(Singleton)。单例通常是跨模块全局的。无正当理由不应使用。
另一个例子是对JS内建对象的prototype的修改。目前的各类模块系统(包括NodeJS)都是不会隔绝的。也就是说,prototype的修改是全局性的,而非局域性的。这也是对内建对象进行prototype扩展必须非常谨慎的根本原因。

而trait通常也应是无状态的。如果有状态,则当前的习惯是使用闭包作为trait的产生器。如果一个trait需要组合其他有状态trait,则它自身通常也随之变为有状态的,也需要套一个闭包作为产生器,产生器接受参数并将参数通过其要组合的trait的产生器传递进去。也就是说,状态是通过产生器被注入进去的。

我本人在一些特殊约束下(如性能考量,因为在产生大量对象时,如果多层trait组合需要大量闭包调用,在IE这样的浏览器中会慢到不可接受),也采用一些折中方式。例如在trait上定义init方法,并通过init方法来初始化状态。当多个具有init方法的trait组合到一起,手工resolve之——实际就是将多个init组合起来。最终init方法应在最终对象实例化后被调用。


当前JavaScript的module系统的设计基本上已经逐渐明晰,其实用性也得到验证。不过trait仍然有很大的发展空间。例如是否应结合type/guard检测?是否trait的手工resolve要求太苛刻而应允许部分妥协(像mixin那样有直接的override机制)?是否应支持私有状态(private)加约定的构造器来取代闭包产生器?诸如此类的问题,可能要等待更多的实践来回答。




2
2
分享到:
评论
1 楼 hastune 2011-10-17  
期待博主写一些关于NodeJS的博文。

相关推荐

    module-tracker.py:跟踪python依赖项的工具

    **与其它Python依赖管理工具的比较** `module-tracker.py` 和其他流行的Python依赖管理工具(如 `pip freeze`,`requirements.txt`,`pipenv` 或 `Poetry`)相比,提供了更详细的依赖分析。虽然这些工具主要用于...

    cocktail-trait-configurable:鸡尾酒延伸特质

    鸡尾酒特质可配置 特性扩展 添加configure(options)方法的特征,该方法将在每个选项键上调用设置器。... '@exports' : module , '@as' : 'class' , '@traits' : [ Configurable ] , '@propert

    cocktail-trait-advisable:将 AOP 方法添加到宿主类的 CocktailJS Trait 扩展

    鸡尾酒特质可取 特性扩展 将 AOP 建议添加到类/对象中的特性。 around 、 after和before方法可用于宿主类或对象。... '@exports' : module , '@as' : 'class' , '@traits' : [ advisable ] , aMet

    WGCNA_1.63.zip_WGCNA_WGCNA quantile_corAndPvalue wgcna_quickly2z

    在WGCNA中,模块的特征被总结为模块trait相关性(Module Trait Relationships, MTR),这有助于识别与研究目标变量(如疾病状态、表型)相关的基因模块。此外,还可以计算模块内的基因与trait之间的平均相关性,即...

    lab-trait-advisable:添加方法建议(之后,之前,周围)实验的特征

    可取的特性(实验性)特性扩展这个 trait 实验旨在将 AOP 建议添加到类中。 around 、 after和before方法可用于宿主类或对象。 有关一些示例,请参阅 example.js ... mix ( { '@exports' : module , '@as' : 'class'

    next-700-module-systems:博士研究; typeclasstrait和recordclassstruct有什么区别? 没什么,所以我认为

    这个主题聚焦于“next-700-module-systems”的博士研究,这可能是一个关于编程语言模块系统的深入探讨。标题和描述中提到了几个关键概念:typeclass、trait和record class/struct。这些是面向对象编程和函数式编程...

    shaku:编译Rust的时间依赖注入库

    use shaku :: {module, Component, Interface, HasComponent}; use std :: sync :: Arc; trait Logger : Interface { fn log ( & self , content: & str ); } trait DateLogger : Interface { fn log_date ( & ...

    The Rust Programming Language.pdf

    10. **trait和泛型(Traits and Generics)**:trait定义了一组方法签名,可以用来实现接口。泛型允许编写通用代码,可以应用于多种类型,提高代码重用性。 11. **模块系统(Module System)**:Rust的模块系统提供...

    8.集成java1

    2. **特性映射** - Scala的某些特性,如特质(trait),在Java中没有直接对应的概念。Scala的泛型虽然与Java的泛型相似,但在实现细节上有所不同。对于这些无法直接映射的特性,Scala编译器会使用特定的编码策略来...

    RustbyExample

    5. ** Trait与泛型**: Rust的trait定义了一组方法签名,可以用于实现多态。泛型允许你在不指定具体类型的情况下编写函数或结构体,从而提高代码的复用性和灵活性。 6. **并发编程**: Rust通过所有权和生命周期系统...

    scala语言规范

    - **继承与多重继承**:Scala 支持单一继承,但通过特质(trait)可以实现多重继承的效果。 - **模版**:类和对象定义时可以包含模板,包含字段、方法和其他成员。 - **访问控制**:Scala 提供 `private`, `...

    php专高一笔记.docx

    - **Trait多继承**:在PHP中,通过使用`trait`可以实现类似多继承的效果,方便代码复用。 - **验证场景**:针对不同的业务场景,可以定义不同的验证规则集。例如,在注册和登录时可能需要不同的验证逻辑。 ##### ...

    the-garden:Scala通用代码

    libraryDependencies + = " me.maciejb.garden " %% " garden-MODULE " % GardenVersion 草地 核心实用程序 可关机 通常情况是,某些应用程序服务将获取非内存资源,这些资源需要在运行应用程序的某个时刻(终止时或...

    Rust语言学习笔记1

    【Rust语言学习笔记1】 ...了解以上基础知识后,可以进一步探索Rust的高级主题,如异步编程、trait(类型特征)、crates(包)管理和并发。通过实践和不断学习,你将能够掌握这个强大而有趣的编程语言。

    Rust基础关键字介绍.docx

    - **`extern`**:与其他语言中的 `extern` 类似,用于声明外部函数或变量,这些函数或变量在 Rust 代码之外定义。例如: ```c extern "C" { fn printf(format: *const u8); } ``` ##### 15. `unsafe` - **`...

    explaine.rs:交互式Rust语法游乐场

    生命周期是Rust中另一个独特的概念,它与引用的存活时间有关。在游乐场中,你可以通过编写涉及字符串切片、变量借用等的例子,直观地看到生命周期对代码的影响。 闭包(closures)是Rust中的函数对象,可以捕获和...

    学习Rust需要的词库.xls

    13. **模块系统(Module System)**: 模块系统用于组织代码,控制作用域和访问权限。 14. **宏(Macros)**: Rust宏提供了一种元编程机制,可以在编译时生成代码。 15. **包(Crates)与库(Libraries)**: Rust...

    rust-doc.vim:搜索Rust文档并使用Vim中的浏览器打开

    打开光标std下单词的文档 使用界面搜索文档用法:RustDoc命令:RustDoc {crate or module name} [{identifier name}]例如,假设您的箱子使用 。 :RustDoc rand打开板条箱rand的文档。 :RustDoc rand::distributions...

    algebraic-structures:在Scala中实现的代数结构

    常见的代数结构包括群(Group)、环(Ring)、域(Field)、模(Module)、交换代数(Commutative Algebra)等。这些结构通常涉及到加法、乘法或其他运算,并且有结合律、交换律、单位元、逆元等性质。 **2. Scala...

    书籍:Rust and WebAssembly书籍

    4. **JavaScript接口**:讲解如何创建JavaScript API来调用WASM模块,包括使用`WebAssembly.instantiateStreaming`和`WebAssembly.Module`对象。 5. **高级Rust和WASM主题**:讨论更复杂的Rust特性,如异步编程、...

Global site tag (gtag.js) - Google Analytics