JS怎麼實作運算子重載
這次帶給大家JS怎麼實作運算子重載,JS實作運算子重載的注意事項有哪些,下面就是實戰案例,一起來看一下。
最近要做資料處理,自訂了一些資料結構,像是Mat,Vector,Point之類的,對於加減乘除之類的四則運算還要重複定義,程式碼顯得不是很直觀,javascript沒有運算子重載這個像C 、C#之類的功能的確令人不爽,於是想“曲線救國”,自動將翻譯代碼實現運算符重載,實現思路其實很簡單,就是編寫一個解釋器,將代碼編譯。例如:
S = A B (B - C.fun())/2 D
翻譯成
`S = replace(replace(A, ' ', replace( replace(B,'',(replace(B,'-',C.fun())))),'/',2),' ',D)`
在replace函數我們呼叫物件對應的運算子函數,replace函數程式碼如下:
/** * 转换方法 * @param a * @param op * @param b * @returns {*} * @private */ export function replace(a,op,b){ if(typeof(a) != 'object' && typeof(b) != 'object'){ return new Function('a','b','return a' + op + 'b')(a,b) } if(!Object.getPrototypeOf(a).isPrototypeOf(b) && Object.getPrototypeOf(b).isPrototypeOf(a)){ throw '不同类型的对象不能使用四则运算' } let target = null if (Object.getPrototypeOf(a).isPrototypeOf(b)) { target = new Function('return ' + b.proto.constructor.name)() } if (Object.getPrototypeOf(b).isPrototypeOf(a)) { target = new Function('return ' + a.proto.constructor.name)() } if (op == '+') { if (target.add != undefined) { return target.add(a, b) }else { throw target.toString() +'\n未定义add方法' } }else if(op == '-') { if (target.plus != undefined) { return target.plus(a, b) }else { throw target.toString() + '\n未定义plus方法' } }else if(op == '*') { if (target.multiply != undefined) { return target.multiply(a, b) }else { throw target.toString() + '\n未定义multiply方法' } } else if (op == '/') { if (target.pide != undefined) { return target.pide(a, b) }else { throw target.toString() + '\n未定义pide方法' } } else if (op == '%') { if (target.mod != undefined) { return target.mod(a, b) }else { throw target.toString() + '\n未定义mod方法' } } else if(op == '.*') { if (target.dot_multiply != undefined) { return target.dot_multiply(a, b) }else { throw target.toString() + '\n未定义dot_multiply方法' } } else if(op == './') { if (target.dot_pide != undefined) { return target.dot_pide(a, b) }else { throw target.toString() + '\n未定义dot_pide方法' } } else if(op == '**') { if (target.power != undefined) { return target.power(a, b) }else { throw target.toString() + '\n未定义power方法' } }else { throw op + '运算符无法识别' } }
replace實作非常簡單,不做過多解釋,重要的部分是如何實作程式碼的編譯。大學學習資料結構時四則運算的實現就是這翻譯的基礎,略微有些差異。簡單描述流程:
1、分割表達式,提取變數和運算子獲得元數組A
2、遍歷元數組
如果元素是運算子加減乘除,則從堆疊中彈出上一個元素,轉換為replace(last,操作符,
如果元素是')',則從堆疊中彈出元素,拼接直到遇到'(',並壓入堆疊。這裡需要注意' ('元素前是否為函數呼叫或replace,如果是函數呼叫或replace,則需要繼續向前彈出數據,閉合replace函數的閉合。
如果是一般元素,則查看前一個元素是否replace,如果是,則需要拼接')'使得replace函數閉合,否則直接將元素壓入堆疊。 #依據上述流程,實作程式碼:
/** * 表达式转换工具方法 * @param code */ export function translate (code) { let data = [] let tmp_code = code.replace(/\s/g,'') let tmp = [] let vari = tmp_code.split(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g) let ops = tmp_code.match(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g) for (let i = 0,len = ops.length; i < len; i++) { if (vari[i] != '') { tmp.push(vari[i]) } if (ops[i] != '') { tmp.push(ops[i]) } } tmp.push(vari[ops.length]) for (let i = 0; i < tmp.length; i++){ let item = tmp[i] if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/.test(tmp[i])) { let top = data.pop() let trans = 'replace(' + top + ',\'' + tmp[i] + '\',' data.push(trans) }else{ if (')' == tmp[i]) { let trans0 = tmp[i] let top0 = data.pop() while (top0 != '(') { trans0 = top0 + trans0 top0 = data.pop() } trans0 = top0 + trans0 let pre = data[data.length - 1] while(/[_\w]+[\.]?[_\w]+/.test(pre) && !/^replace\(/.test(pre) && pre != undefined) { pre = data.pop() trans0 = pre + trans0 pre = data[data.length - 1] } pre = data[data.length - 1] while(pre != undefined && /^replace\(/.test(pre)){ pre = data.pop() trans0 = pre + trans0 + ')' pre = data[data.length - 1] } data.push(trans0) }else { let pre = data[data.length - 1] let trans1 = tmp[i] while(pre != undefined && /^replace\(/.test(pre) && !/\*\*|\+|-|\*|\/|\(|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|=|\}|%|\.\/|\.\*/.test(item) && !/^replace\(/.test(item)) { if(tmp[i + 1] == undefined){ pre = data.pop() trans1 = pre + trans1 + ')' break; }else{ pre = data.pop() trans1 = pre + trans1 + ')' pre = data[data.length - 1] } } data.push(trans1) } } } let result = '' data.forEach((value, key, own) => { result += value }) return result }
表達式編譯的方法寫好了,接下來就是如何使編寫的程式碼被我們的翻譯機翻譯,也就是需要一個容器,兩種方法:一種就是類別建構器重新定義方法屬性,另一種就是將程式碼作為參數傳入我們自訂的方法。 ,我們使用Object.defineProperty在建構器中重新定義了,translate_block是對整個程式碼區塊分割得到進行翻譯,程式碼如下:
export default class OOkay { constructor () { let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(this)) protos.forEach((proto, key, own) => { if(proto != 'constructor'){ Object.defineProperty(this, proto, { value:new Function(translate_block(proto, this[proto].toString())).call(this) }) } }) } }
對於新的類,我們只要繼承OOkay類別就可以在該類中
使用運算子重載。我採用了兩種方式,一種以ookay腳本的方式使用,像這樣
還有就是將程式碼作為參數傳入$$方法,該方法編譯程式碼並執行,如下:/**
* 类代码块转换工具
* @param name
* @param block
* @returns {string}
*/
export function translate_block (name , block) {
let codes = block.split('\n')
let reg = new RegExp('^' + name + '$')
console.log(reg.source)
codes[0] = codes[0].replace(name,'function')
for(let i = 1; i < codes.length; i++) {
if (codes[i].indexOf('//') != -1) {
codes[i] = codes[i].substring(0,codes[i].indexOf('//'))
}
if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/g.test(codes[i])){
if (codes[i].indexOf('return ') != -1) {
let ret_index = codes[i].indexOf('return ') + 7
codes[i] = codes[i].substring(0,ret_index) + translate(codes[i].substring(ret_index))
}else {
let eq_index = codes[i].indexOf('=') + 1
codes[i] = codes[i].substring(0,eq_index) + translate(codes[i].substring(eq_index))
}
}
}
return 'return ' + codes.join('\n')
}
nodejs透過回應回寫渲染頁面步驟詳解
以上是JS怎麼實作運算子重載的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

華為手機如何實現雙微信登入?隨著社群媒體的興起,微信已成為人們日常生活中不可或缺的溝通工具之一。然而,許多人可能會遇到一個問題:在同一部手機上同時登入多個微信帳號。對於華為手機用戶來說,實現雙微信登入並不困難,本文將介紹華為手機如何實現雙微信登入的方法。首先,華為手機自帶的EMUI系統提供了一個很方便的功能-應用程式雙開。透過應用程式雙開功能,用戶可以在手機上同

程式語言PHP是一種用於Web開發的強大工具,能夠支援多種不同的程式設計邏輯和演算法。其中,實作斐波那契數列是一個常見且經典的程式設計問題。在這篇文章中,將介紹如何使用PHP程式語言來實作斐波那契數列的方法,並附上具體的程式碼範例。斐波那契數列是一個數學上的序列,其定義如下:數列的第一個和第二個元素為1,從第三個元素開始,每個元素的值等於前兩個元素的和。數列的前幾元

如何在華為手機上實現微信分身功能隨著社群軟體的普及和人們對隱私安全的日益重視,微信分身功能逐漸成為人們關注的焦點。微信分身功能可以幫助使用者在同一台手機上同時登入多個微信帳號,方便管理和使用。在華為手機上實現微信分身功能並不困難,只需要按照以下步驟操作即可。第一步:確保手機系統版本和微信版本符合要求首先,確保你的華為手機系統版本已更新至最新版本,以及微信App

在現今的軟體開發領域中,Golang(Go語言)作為一種高效、簡潔、並發性強的程式語言,越來越受到開發者的青睞。其豐富的標準庫和高效的並發特性使它成為遊戲開發領域的一個備受關注的選擇。本文將探討如何利用Golang來實現遊戲開發,並透過具體的程式碼範例來展示其強大的可能性。 1.Golang在遊戲開發中的優勢作為靜態類型語言,Golang正在建構大型遊戲系統

PHP遊戲需求實現指南隨著網路的普及和發展,網頁遊戲的市場也越來越火爆。許多開發者希望利用PHP語言來開發自己的網頁遊戲,而實現遊戲需求是其中一個關鍵步驟。本文將介紹如何利用PHP語言來實現常見的遊戲需求,並提供具體的程式碼範例。 1.創造遊戲角色在網頁遊戲中,遊戲角色是非常重要的元素。我們需要定義遊戲角色的屬性,例如姓名、等級、經驗值等,並提供方法來操作這些

在Golang中實現精確除法運算是一個常見的需求,特別是在涉及金融計算或其它需要高精度計算的場景中。 Golang的內建的除法運算子「/」是針對浮點數計算的,並且有時會出現精度遺失的問題。為了解決這個問題,我們可以藉助第三方函式庫或自訂函數來實現精確除法運算。一種常見的方法是使用math/big套件中的Rat類型,它提供了分數的表示形式,可以用來實現精確的除法運算

python憑藉其簡單易讀的語法,廣泛應用於廣泛的領域。掌握Python語法的基礎架構至關重要,既可以提高程式效率,又能深入理解程式碼的運作方式。為此,本文提供了一個全面的心智圖,詳細闡述了Python語法的各個面向。變數和資料類型變數是Python中用於儲存資料的容器。心智圖展示了常見的Python資料類型,包括整數、浮點數、字串、布林值和列表。每個資料類型都有其自身的特性和操作方法。運算符運算符用於對資料類型執行各種操作。心智圖涵蓋了Python中的不同運算子類型,例如算術運算子、比
