尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从零打造可重载类型:proposal-operator-overloading 开发者指南之 Operators 工厂函数详解

从零打造可重载类型:proposal-operator-overloading 开发者指南之 Operators 工厂函数详解 从零打造可重载类型proposal-operator-overloading 开发者指南之 Operators 工厂函数详解【免费下载链接】proposal-operator-overloading项目地址: https://gitcode.com/gh_mirrors/pr/proposal-operator-overloadingJavaScript 的运算符重载提案 proposal-operator-overloading 想要让开发者自定义、*等运算符的行为而整个提案的入口就是名为Operators的工厂函数。本指南将带你从零理解Operators工厂函数的工作方式如何用它定义运算符、创建可重载类型以及如何让自定义类型与Number、String等内置类型协同运算。即使你是运算符重载的新手也能按步骤掌握这套 API 的核心用法。什么是 Operators 工厂函数在 proposal-operator-overloading 中Operators是一个工厂函数你向它传入一份运算符定义表一个普通的对象它就会返回一个基类。你只需要让自定义类继承这个基类你的类型就自动拥有了可重载的运算符能力。它的推荐用法非常简洁const operators Operators(operatorDefinitions); class MyClass extends operators { /* ... */ } Object.preventExtensions(MyClass);关键点在于Operators的第一个参数是必需的它是一份键为运算符名如、*、、值为实现函数的字典。每个实现函数接收两个操作数并返回运算结果。快速上手从零创建一个可重载类型以提案中最经典的Vector向量为例我们希望new Vector([1,2,3]) new Vector([4,5,6])能得到逐元素相加的新向量const VectorOps Operators({ (a, b) { return new Vector(a.contents.map((elt, i) elt b.contents[i])); }, (a, b) { return a.contents.length b.contents.length a.contents.every((elt, i) elt b.contents[i]); } }); export class Vector extends VectorOps { constructor(contents) { super(); this.contents contents; } } Object.preventExtensions(Vector);这里有两个容易被新手忽略的细节继承之后要调用super()因为运算符定义内部槽是在基类构造函数里写入的用Object.preventExtensions(Vector)冻结类确保运算符定义不会被后续代码篡改。这个模式在提案文档的 Decimal 与 Vector 示例 中反复出现建议对照阅读。跨类型运算符理解 left 与 right 参数Operators工厂函数的神奇之处在于除了第一份定义表你还可以传入额外的参数用来描述当操作数中一个是已定义类型、另一个是其他类型时的行为。每个额外参数必须以left:或right:开头指明另一侧操作数的类型。例如实现Number * Vector数字在左const VectorOps Operators({ (a, b) { /* ... */ } }, { left: Number, *(a, b) { return new Vector(b.contents.map(elt elt * a)); } });left: Number表示这张表处理Number在左侧的情形即2 * vector若写right: Number则处理vector * 2的情形。这种按左右操作数分别分发multiple dispatch的设计正是Operators工厂函数区别于 Python 等语言运算符重载方案的核心特色。在 shim.js 的 partitionTables 函数 中可以看到它如何把传入的表按left/right拆分成两个内部查找表。注意同一张表不能同时声明left和right否则会抛出TypeError。open 属性控制可被重载的运算符范围出于可读性考量提案并不允许你重载所有运算符。Operators工厂函数的定义表里还支持一个特殊的open属性用来声明这个类型允许其他类型对它重载哪些运算符const OpsA Operators({ open: [] });内置类型如Number、BigInt默认开放所有二元运算符而String只开放、、如果你的类型没有声明open其他类型就不能针对它定义跨类型重载。例如 shim.spec.js 的 Open set handling 用例就演示了只有声明open: []后OpsB才能为OpsA定义的跨类型行为。支持哪些运算符一张清单看清楚Operators工厂函数可以重载的运算符分为三类详见 shim.js 顶部的运算符表类别运算符二元数学-*/%**位运算^\|一元pos正号neg负号--~比较由推导下标可选[][]值得注意的是、、不需要单独实现它们由自动推导而、!、、||等不支持重载这保证了语言行为可预测。若在定义表中声明了[]或[]Operators返回的类会自动用Proxy实现整数下标访问这也是 shim.js 中最复杂的部分。让重载真正生效配合 with operators from定义好运算符还不够——默认情况下重载是未启用的。使用时必须通过with operators from声明在 shim 中对应withOperatorsFrom()函数显式开启withOperatorsFrom(Vector); // 启用 Vector 的运算符 new Vector([1,2,3]) new Vector([4,5,6]); // 生效这个多一步摩擦的设计是提案刻意为之只有明确声明重载才会生效避免库使用者在不经意间改变既有代码的行为。启用范围基于块级作用域你也可以只在一个函数内部开启。在真实项目中你需要同时使用两个 npm 包来体验完整能力littledan/operator-overloading-shim运行时支持导出Operators工厂函数源码见 src/shim/shim.jslittledan/plugin-transform-operator-overloadingBabel 插件把withOperatorsFrom()和表达式转换为 shim 调用源码见 src/transform/plugin.js。安装与配置说明都在 transform/README.md 中只需要两条npm install命令加一行.babelrc配置即可跑起来。进阶装饰器风格 API 与常见误区除了命令式调用Operators还提供了装饰器风格 APIOperators.overloaded()标记整个类可重载Operators.define()逐个定义运算符方法见 shim.js 中的实现。两条路径最终殊途同归都会汇聚到Operators(...args)这个核心函数上。新手常踩的几个坑提前帮你避开忘记super()Vector构造函数不调用super()运算符内部槽就不会被写入运行时报未找到重载混淆left与rightleft: Number针对number 在左写反会导致2 * vec与vec * 2行为颠倒期望重载永远使用严格相等语义请改用或额外提供方法接口过度使用重载提案建议库同时暴露基于方法的接口如vec.add()以便不支持转换的环境也能使用。结语Operators工厂函数是 proposal-operator-overloading 提案中设计最精巧的部分一份定义表 left/right分发 open控制就为 JavaScript 带来了克制而强大的运算符重载能力。无论是数值类型、向量矩阵还是 DSL 公式掌握了这个工厂函数你就拿到了从零打造可重载类型的钥匙。想深入了解底层规范可以继续阅读 PROTOSPEC.md或对照 语言对比文档 了解它与 C、Python、Matlab 等语言方案的异同。【免费下载链接】proposal-operator-overloading项目地址: https://gitcode.com/gh_mirrors/pr/proposal-operator-overloading创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表