Skip to content

Instantly share code, notes, and snippets.

@akira-cn
Created June 10, 2022 03:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akira-cn/ea27bdd6a122b0d90acdf59e4b5aaf21 to your computer and use it in GitHub Desktop.
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)
*/
@akira-cn
Copy link
Author

akira-cn commented Jun 10, 2022

运算符重载不改变运算优先级,暂不考虑[ ].... 等操作符的重载

@akira-cn
Copy link
Author

单、双目同名运算符,如-,可以通过 operands.length 判断

这样不会混淆 -aa-undefined

@akira-cn
Copy link
Author

引擎实现的时候,运行时需要判断两次对象方法,但是可以根据代码Lexical静态判断有没有定义Symbol.operation方法以及定义在哪个类型上,锁定需要判断的对象类型,这样不会导致额外性能开销

@akira-cn
Copy link
Author

对于primitive types,可以考虑一下是否要支持运算符重载(感觉意义不大)
比如定义了 Number[Symbol.operation] 方法,是否对所有number类型的操作调用 Number[Symbol.operation]

@hax
Copy link

hax commented Jun 10, 2022

primitive肯定不应该的,目前spec里可基于symbol定制的行为我记得绝大多数对于primitive都是无效的。而且改变primitive的行为不仅对开发者来说会引入混淆,也会影响引擎性能。

@hax
Copy link

hax commented Jun 10, 2022

static 的话,那就是 Complex[Symbol.operation] ,有个问题,对于 x + y来说,其实没有可靠方法从x对象得到Complexconstructor并不是一个可靠的属性,除非手动设定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)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment