-
-
Save akira-cn/ea27bdd6a122b0d90acdf59e4b5aaf21 to your computer and use it in GitHub Desktop.
class Complex { | |
#r = 0; | |
#i = 0; | |
get r() { | |
return this.#r; | |
} | |
set r(value) { | |
this.#r = value; | |
} | |
get i() { | |
return this.#i; | |
} | |
set i(value) { | |
this.#i = value; | |
} | |
static [Symbol.operation](operator, ...operands) { | |
const [a, b] = operands; | |
if(operator === '+') { | |
if(a instanceof Complex && typeof b === 'number') { | |
return new Complex(a.r + b, a.i); | |
} else if(a instanceof Complex && b instanceof Complex) { | |
return new Complex(a.r + b.r, a.i + b.i); | |
} else if(typeof a === 'number' && b instanceof Complex) { | |
return new Complex(a + b.r, b.i); | |
} | |
throw new TypeError("xxxx"); | |
} | |
// ... | |
} | |
} | |
/** | |
* Symbol.operation 只能定义为 static 方法 | |
* 在双目运算中,先判断左操作数的类型上有没有Symbol.operation方法 | |
* 有的话 LeftClass[Symbol.operation](operator, left, right) | |
* 再判断右操作数的类型上有没有 Symbol.operation 方法 | |
* 有的话 RightClass[Symbol.operation](operator, left, right) | |
* 单目运算符如果操作数类型上有Symbol.operation方法 | |
* OperandClass[Symbol.operation](operator, operand) | |
*/ |
单、双目同名运算符,如-
,可以通过 operands.length 判断
这样不会混淆 -a
和 a-undefined
引擎实现的时候,运行时需要判断两次对象方法,但是可以根据代码Lexical静态判断有没有定义Symbol.operation方法以及定义在哪个类型上,锁定需要判断的对象类型,这样不会导致额外性能开销
对于primitive types,可以考虑一下是否要支持运算符重载(感觉意义不大)
比如定义了 Number[Symbol.operation]
方法,是否对所有number类型的操作调用 Number[Symbol.operation]
primitive肯定不应该的,目前spec里可基于symbol定制的行为我记得绝大多数对于primitive都是无效的。而且改变primitive的行为不仅对开发者来说会引入混淆,也会影响引擎性能。
static 的话,那就是 Complex[Symbol.operation]
,有个问题,对于 x + y
来说,其实没有可靠方法从x
对象得到Complex
。constructor
并不是一个可靠的属性,除非手动设定writable:false、configurable:false。或者引入额外的internal slot来保存对象的类型。比较来说,prototype上的symbol会比较简单,因为那就是普通属性访问,和现在的Symbol.toPrimitive差不多。
现在的 x + y
的逻辑就是先看一下 x 和 y 的 type,如果x是object,就会走 x[Symbol.toPrimitive]("default")
(除了加法以外的会走 x[Symbol.toPrimitive]("number")
)。y也一样。那么如果加上基于symbol的operator overload,则就先调用 x[Symbol.op](y)
,没有的话再fallback到现在的 toPrimitive。
此外相比单一的Symbol.operation,单独的Symbol.plus、Symbol.minus等会效率更高,且消除了单目和双目的问题(因为可以分别有单独的symbol)。
运算符重载不改变运算优先级,暂不考虑
[ ]
、.
、...
等操作符的重载