JavaScript 模擬向量運算符重載

keitaflq 8年前發布 | 9K 次閱讀 向量 JavaScript開發 JavaScript

來自: http://www.w3ctech.com/topic/1695

寫在前面, 本文中實現的運算符重載有很多局限, 完全不能實用, 僅供燒腦和娛樂.

</div>

很久以前做過比較完善的 函數重載實現 , 然后自從知道 valueOf 這個東西, 就一直有想搞運算符重載的念頭. 搜了下居然搜到自己 11 年發的 帖子 , 對 valueOf 進行了簡單的利用.

前些時候在公司做分享, 主題是 WAT JavaScript Explained, 最后是以 JavaScript 嘗試重載向量的 +-*/ 運算符結束的, 下文則是在分享中設計的效果與方法.

效果

第一種實現

Vector.createVector('a', 1, 2);
Vector.createVector('b', 4, 6);
Vector.createVector('c');

c = a + b; c = a - b; c = a * 2; c = b / 4;</pre>

第二種實現

Vector.createVector('a', 1, 2);
Vector.createVector('b', 4, 6);
Vector.createVector('c', 2, 1);
Vector.createVector('d');

d = a + b - c; d = -a - b + c;</pre>

文中的技巧還可以實現類似的效果:

let a = new Vector(1, 2);
let b = new Vector(4, 6);
let c = new Vector(4, 6);
let d = calc(a + b - c);

方法

細心的同學可能已經發現, 上面提到的例子中, 要么使用了全局變量, 要么需要包裹一個函數 calc . 通過重寫 valueOf 方法, 我們可以知道哪些向量參與了運算. 但僅僅如此, 還無法知道參與運算的運算符, 也無法知道第一種實現中類似于 a * 2 和 b / 4 中的 2 和 4 . 但如果我們可以獲得整個表達式的值, 就可以從某種程度窺探發生了怎樣的運算.

兩個向量的 + 和 -

前面我們提到了重寫 valueOf 方法獲取參與了運算的向量, 但為了知道發生了怎樣的運算, 我們還需要為 valueOf 構造特別的返回值. 比如第一個參與運算的向量 a 對應的值為 1 , 第二個向量 b 對應的值為 2 , 那么 a + b 的值則為 3 , a - b 則為 -1 . 這樣一來, 通過 setter 或者 calc 函數我們就可以根據表達式的值得知發生了什么運算.

雖然只提到了 + 和 - , 同樣的方法我們還可以實現向量的叉乘.

一個向量一個標量的 * 和 /

對于四則運算中的原始值, JavaScript 并不會調用對應的 valueOf . 這樣一來, 我們則需要爭取通過獲得的表達式的值獲取運算符和標量. 或者, 或許我們并不需要知道到底是哪一個運算符, 只需要知道這個向量需要縮放的比例. 上面我們提到了第一個參與運算的向量 valueOf 的值是 1 , 這自然而然地帶來了一個好處: 表達式 a * n ( a 為向量, n 為標量) 的值是 n , b / m ( b 為向量, m 為標量) 的值則是 1 / m . 向量需要縮放的比例正好是表達式最后的值! 現在知道了參與運算的向量和它需要被縮放的比例, 也就自然可以計算出結果.

多個向量的 + 和 -

上面提到的方式中, 構造 valueOf 的值相對簡單, 只要不為零都是可以的. 然而很顯然, 如果向量數量大于 2, 這種構造的方式得出的表達式的值很難再推出發生了哪些運算. 不過僅僅是針對 + 和 - 兩種運算, 我們還是有辦法區分一定數量的向量參的運算.

思考表達式 a + b - c + d - e , 怎樣可以使它的值包含所有的運算符信息? 可能有的同學也會立即把它和 flags 或者 enums 之類的聯系到一起:

let flagA = 0b0001;
let flagB = 0b0010;

let flagAB = flagA | flagB; // 0b0011</pre>

如果我們可以把類似的性質應用到加減上, 就可以保留一定數量的運算符信息了. 考慮三進制數的加減: 1111 + 1 - 10 + 100 - 1000 = 0202. 和表達式 a + b - c + d - e 聯系起來, 0202 中的四個數字分別對應了 - ( e ), + ( d ), - ( c ) 和 + ( b ).

這樣一來, 我們為第一個參與運算的向量構建足夠大的每一位都為 1 的三進制數作為 valueOf 的返回值, 為隨后參與運算的向量分別構建 1, 10, 100 這樣的三進制數, 就可以通過表達式的值獲知幾十個參與運算的向量對應的符號了. 對于首個元素前面有負號的情況, 則可以通過整個表達式的正負來做區分.

實現

上面提到的兩種效果的實現都可以在這個倉庫找到: vilic/js-operator-overloading .

掃碼關注w3ctech微信公眾號

 本文由用戶 keitaflq 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!