Maison > Article > interface Web > Comment utiliser la surcharge des opérateurs
Cette fois, je vais vous montrer comment utiliser la surcharge d'opérateur et quelles sont les précautions à prendre pour utiliser la surcharge d'opérateur. Ce qui suit est un cas pratique, jetons un coup d'œil.
J'ai récemment fait du traitement de données et j'ai personnalisé certaines structures de données, telles que Mat, Vector, Point, etc. Je dois définir à plusieurs reprises les quatre opérations arithmétiques telles que l'addition, la soustraction, multiplication et division, code Cela ne semble pas très intuitif. JavaScript n'a pas de surcharge d'opérateurs, ce qui est une fonction comme C++ et C#. C'est vraiment ennuyeux, donc je veux « sauver le pays » en implémentant automatiquement la surcharge d'opérateurs dans le code. code de traduction. L'idée d'implémentation est en fait très simple, il suffit d'écrire un interpréteur. Par exemple :
S = A + B (B - C.fun())/2 + D
se traduit par
`S = remplacer (remplacer(A, '+', remplacer(remplacer(B,'',(remplacer(B,'-',C.fun())))),'/',2),'+',D ) `
Dans la fonction replace nous appelons 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. Explication, la partie importante est de savoir comment implémenter la compilation du 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 de fonction ou d'un remplacement, 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 }Comme le montre ce qui précède, nous utilisons Object.defineProperty pour le redéfinir dans le constructeur Translate_block, c'est-à-dire diviser le bloc de code entier et le traduire. est la suivante :
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) }) } }) } }Pour les nouvelles classes, nous n'avons besoin que d'hériter. La classe OOkay peut utiliser la surcharge d'opérateurs dans cette classe. Pour celles qui héritent de classes non-OOOkay, nous pouvons utiliser l'injection, comme suit. :
/** * 类代码块转换工具 * @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 le code dans les non-classes, nous avons besoin d'un conteneur. J'ai utilisé deux méthodes ici, l'une utilise un script ookay, comme celui-ci
/** * 非继承类的注入方法 * @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) }) } }) }
static __$__(fn) { if(!(fn instanceof Function)){ throw '参数错误' } (new Function(translate_block('function',fn.toString()))).call(window)() }
Lecture recommandée :
Vue+Nuxt.js effectue un rendu côté serveurAngular utilise l'analyse du code HMRCe 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!