日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

php如何实现运算符重载,JS怎样实现运算符重载

發(fā)布時(shí)間:2023/12/31 php 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php如何实现运算符重载,JS怎样实现运算符重载 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這次給大家?guī)?lái)JS怎樣實(shí)現(xiàn)運(yùn)算符重載,JS實(shí)現(xiàn)運(yùn)算符重載的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來(lái)看一下。

最近要做數(shù)據(jù)處理,自定義了一些數(shù)據(jù)結(jié)構(gòu),比如Mat,Vector,Point之類(lèi)的,對(duì)于加減乘除之類(lèi)的四則運(yùn)算還要重復(fù)定義,代碼顯得不是很直觀,javascript沒(méi)有運(yùn)算符重載這個(gè)像C++、C#之類(lèi)的功能的確令人不爽,于是想“曲線(xiàn)救國(guó)”,自動(dòng)將翻譯代碼實(shí)現(xiàn)運(yùn)算符重載,實(shí)現(xiàn)思路其實(shí)很簡(jiǎn)單,就是編寫(xiě)一個(gè)解釋器,將代碼編譯。例如:

S = A + B (B - C.fun())/2 + D

翻譯成

`S = replace(replace(A, '+', replace(replace(B,'',(replace(B,'-',C.fun())))),'/',2),'+',D)`

在replace函數(shù)中我們調(diào)用對(duì)象相應(yīng)的運(yùn)算符函數(shù),replace函數(shù)代碼如下:/**

* 轉(zhuǎn)換方法

* @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 '不同類(lèi)型的對(duì)象不能使用四則運(yùn)算'

}

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 + '運(yùn)算符無(wú)法識(shí)別'

}

}

replace實(shí)現(xiàn)非常簡(jiǎn)單,不做過(guò)多解釋,重要的部分是如何實(shí)現(xiàn)代碼的編譯。大學(xué)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)時(shí)四則運(yùn)算的實(shí)現(xiàn)就是這翻譯的基礎(chǔ),略微有些差異。簡(jiǎn)單描述一下流程:

1、分割表達(dá)式,提取變量和運(yùn)算符獲得元數(shù)組A

2、遍歷元數(shù)組

如果元素是運(yùn)算符加減乘除,則從堆棧中彈出上一個(gè)元素,轉(zhuǎn)換為replace(last,操作符,

如果元素是‘)',則從堆棧中彈出元素,拼接直到遇到'(',并壓入堆棧。這里需要注意‘('元素前是否為函數(shù)調(diào)用或replace,如果是函數(shù)調(diào)用或replace,則需要繼續(xù)向前彈出數(shù)據(jù),閉合replace函數(shù)的閉合。

如果是一般元素,則查看前一個(gè)元素是否replace,如果是,則需要拼接‘)'使得replace函數(shù)閉合,否則直接將元素壓入棧。

3、將2步驟中得到的棧順序組合就得到編譯后的表達(dá)式。

依據(jù)上述流程,實(shí)現(xiàn)代碼:/**

* 表達(dá)式轉(zhuǎn)換工具方法

* @param code

*/

export function translate (code) {

let data = []

let tmp_code = code.replace(/\s/g,'')

let tmp = []

let vari = tmp_code.split(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|

let ops = tmp_code.match(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|

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)

&& !/\*\*|\+|-|\*|\/|\(|\?|>[=]|

&& !/^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

}

表達(dá)式編譯的方法寫(xiě)好了,接下來(lái)就是如何使編寫(xiě)的代碼被我們的翻譯機(jī)翻譯,也就是需要一個(gè)容器,兩種方法:一種就是類(lèi)構(gòu)造器重新定義方法屬性,另一種就是將代碼作為參數(shù)傳入我們自定義的方法。接下來(lái)介紹一下類(lèi)構(gòu)造器中重新定義方法: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)

})

}

})

}

}

由上面可以看出,我們使用Object.defineProperty在構(gòu)造器中重新定義了,translate_block是對(duì)整個(gè)代碼塊分割得到進(jìn)行翻譯,代碼如下:/**

* 類(lèi)代碼塊轉(zhuǎn)換工具

* @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')

}

對(duì)于新的類(lèi),我們只要繼承OOkay類(lèi)就可以在該類(lèi)中使用運(yùn)算符重載。對(duì)于繼承自非OOkay類(lèi)的,我們可以采用注入的方式,如下:/**

* 非繼承類(lèi)的注入方法

* @param target

*/

static inject (target) {

let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(target))

protos.forEach((proto, key, own) => {

if (proto != 'constructor') {

Object.defineProperty(target, proto, {

value:new Function(translate_block(proto, target[proto].toString())).call(target)

})

}

})

}

對(duì)于非類(lèi)中的代碼,我們需要一個(gè)容器,這里我采用了兩種方式,一種以ookay腳本的方式使用,像這樣

let a = a+b // a、b為對(duì)象實(shí)例

還有就是將代碼作為參數(shù)傳入$$方法,該方法編譯代碼并執(zhí)行,如下:static $(fn) {

if(!(fn instanceof Function)){

throw '參數(shù)錯(cuò)誤'

}

(new Function(translate_block('function',fn.toString()))).call(window)()

}

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!

推薦閱讀:

總結(jié)

以上是生活随笔為你收集整理的php如何实现运算符重载,JS怎样实现运算符重载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。