Cette fois, je vais vous montrer comment implémenter la surcharge d'opérateur en JS, et quelles sont les notes pour implémenter la surcharge d'opérateur en JS Voici un cas pratique, prenons un. regarder.
J'ai récemment fait du traitement de données et j'ai personnalisé certaines structures de données, telles que Mat, Vecteur, Point, etc. Je dois définir à plusieurs reprises les quatre opérations arithmétiques telles que l'addition, la soustraction, la multiplication et la division. ne semble pas très intuitif, javascript Le manque de surcharge d'opérateurs, une fonctionnalité comme C++ et C#, est vraiment frustrant, j'ai donc voulu "sauver le pays" en implémentant automatiquement la surcharge d'opérateurs dans le code de traduction. L'idée d'implémentation est en fait très simple. , qui consiste à écrire un interpréteur et à compiler le code. Par exemple :
S = A + B (B - C.fun())/2 + D
se traduit par
`S = replace(replace(A , ' +', replace(replace(B,'',(replace(B,'-',C.fun())))),'/',2),'+',D)`
Dans la fonction replace, on appelle la fonction opérateur correspondante de l'objet. Le code de la fonction replace est le suivant :
/** * 转换方法 * @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 + '运算符无法识别' } }
La mise en œuvre du remplacement est très simple, sans trop d'explications, l'important. une partie est de savoir comment compiler le code. La mise en œuvre des quatre opérations arithmétiques lors de l’étude de la structure des données au collège constitue la base de cette traduction, avec de légères différences. Décrivez brièvement le processus :
1. Divisez l'expression, extrayez les variables et les opérateurs pour obtenir le méta-tableau A
2 Parcourez le méta-tableau
Si les éléments sont des opérateurs d'addition, de soustraction, de multiplication. et division, puis extrayez l'élément précédent de la pile et convertissez-le en remplacement (dernier, opérateur,
Si l'élément est ')', extrayez l'élément de la pile, épissez-le jusqu'à ce qu'il rencontre '(' et appuyez sur dans la pile. Notez ici '(' Y a-t-il un appel de fonction ou un remplacement avant l'élément ? S'il s'agit d'un appel ou d'un remplacement de fonction, vous devez continuer à faire avancer les données et fermer la fonction de remplacement.
Si c'est le cas. est un élément général, vérifiez si l'élément précédent est remplacé. Si oui, vous devez épisser ')' pour fermer la fonction de remplacement, sinon poussez l'élément directement sur la pile
3. obtenu à l'étape 2 pour obtenir l'expression compilée. 🎜>Selon le processus ci-dessus, implémentez le code :
La méthode de compilation de l'expression a été écrite. L'étape suivante consiste à traduire le code écrit. par notre traducteur, c'est-à-dire qu'un conteneur est nécessaire, deux types Méthode : L'une consiste à redéfinir les attributs de la méthode dans le constructeur de classe et l'autre consiste à transmettre le code en tant que paramètre à notre méthode personnalisée. Ensuite, nous présenterons le. méthode redéfinie dans le constructeur de classe :/** * 表达式转换工具方法 * @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 }
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) }) } }) } }
/** * 类代码块转换工具 * @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') }
Pour les non-classes, nous avons besoin d'un conteneur Ici, j'utilise deux méthodes. L'une utilise un script ookay, comme ceci
static $(fn) { if(!(fn instanceof Function)){ throw '参数错误' } (new Function(translate_block('function',fn.toString()))).call(window)() }
Comment créer du cross-domain avec vue-cli ! Demande
Explication détaillée du terminal mobile webpack automatisé étapes de construction de rem
Explication détaillée de la page de rendu nodejs via l'écriture de réponse
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!