Detailed explanation of operator overloading in Javascript
This article summarizes and introduces the method of implementing operator overloading in Javascript. The implementation idea is very simple. Friends who need it can take a look.
I have recently done data processing and customized some data structures. For example, Mat, Vector, Point, etc., the four arithmetic operations such as addition, subtraction, multiplication and division have to be repeatedly defined. The code is not very intuitive. It is really annoying that JavaScript does not have operator overloading like C and C#, so I thought "Curve to save the country" automatically implements operator overloading in the translation code. The implementation idea is actually very simple, which is to write an interpreter and compile the code. For example:
S = A B (B - C.fun())/2 D
is translated into
`S = replace( replace(A, ' ', replace(replace(B,'',(replace(B,'-',C.fun())))),'/',2),' ',D)`
In the replace function we call the corresponding operator function of the object. The replace function code is as follows:
/** * 转换方法 * @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 + '运算符无法识别' } }
The replacement implementation is very simple. There is too much explanation, the important part is how to compile the code. The implementation of the four arithmetic operations when studying data structure in college is the basis of this translation, with slight differences. Briefly describe the process:
1. Split the expression, extract variables and operators to obtain the metaarray A
2. Traverse the metaarray
If the element is an operator addition, subtraction, multiplication and division , pop the previous element from the stack and convert it to replace(last, operator,
If the element is ')', pop the element from the stack, splice it until it encounters '(', and push it into the stack. Here You need to pay attention to whether the '(' element is preceded by a function call or replace. If it is a function call or replace, you need to continue to pop the data forward and close the replace function.
If it is a general element, check whether the previous element is replaced , if so, you need to splice ')' to close the replace function, otherwise push the element directly onto the stack.
3. Combine the stack sequence obtained in step 2 to get the compiled expression .
According to the above process, implement the code:
/** * 表达式转换工具方法 * @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 }
The expression compilation method is written, and the next step is how to use it. The written code is translated by our translator, which means a container is needed. Two methods: one is to redefine the method attributes with the class constructor, and the other is to pass the code as a parameter into our custom method. Next, we will introduce Redefine the method in the class constructor:
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) }) } }) } }
As can be seen from the above, we use Object.defineProperty to redefine it in the constructor, and translate_block is The entire code block is divided and translated. The code is as follows:
/** * 类代码块转换工具 * @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') }
For new classes, we can use operator overloading in this class as long as we inherit the OOkay class. For code that inherits from non-OOkay classes, we can use injection, as follows:
/** * 非继承类的注入方法 * @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) }) } }) }
For code in non-classes, we need a container, here I Two methods are used, one is used as an ookay script, like this
Another option is to pass the code as a parameter into the __$$__ method, which compiles the code and executes it, as follows:
static __$__(fn) { if(!(fn instanceof Function)){ throw '参数错误' } (new Function(translate_block('function',fn.toString()))).call(window)() }
The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.
Related articles:
How to solve the problem of Chinese garbled characters when JQuery ajax returns json
How the Django framework uses the ajax post method
##Solution to the 403 error when using jquery ajax post data in django
The above is the detailed content of Detailed explanation of operator overloading in Javascript. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Face detection and recognition technology is already a relatively mature and widely used technology. Currently, the most widely used Internet application language is JS. Implementing face detection and recognition on the Web front-end has advantages and disadvantages compared to back-end face recognition. Advantages include reducing network interaction and real-time recognition, which greatly shortens user waiting time and improves user experience; disadvantages include: being limited by model size, the accuracy is also limited. How to use js to implement face detection on the web? In order to implement face recognition on the Web, you need to be familiar with related programming languages and technologies, such as JavaScript, HTML, CSS, WebRTC, etc. At the same time, you also need to master relevant computer vision and artificial intelligence technologies. It is worth noting that due to the design of the Web side

The += operator is used to add the value of the left operand to the value of the right operand and assign the result to the left operand. It is suitable for numeric types and the left operand must be writable.

With the rapid development of Internet finance, stock investment has become the choice of more and more people. In stock trading, candle charts are a commonly used technical analysis method. It can show the changing trend of stock prices and help investors make more accurate decisions. This article will introduce the development skills of PHP and JS, lead readers to understand how to draw stock candle charts, and provide specific code examples. 1. Understanding Stock Candle Charts Before introducing how to draw stock candle charts, we first need to understand what a candle chart is. Candlestick charts were developed by the Japanese

Python is widely used in a wide range of fields with its simple and easy-to-read syntax. It is crucial to master the basic structure of Python syntax, both to improve programming efficiency and to gain a deep understanding of how the code works. To this end, this article provides a comprehensive mind map detailing various aspects of Python syntax. Variables and Data Types Variables are containers used to store data in Python. The mind map shows common Python data types, including integers, floating point numbers, strings, Boolean values, and lists. Each data type has its own characteristics and operation methods. Operators Operators are used to perform various operations on data types. The mind map covers the different operator types in Python, such as arithmetic operators, ratio

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

The relationship between js and vue: 1. JS as the cornerstone of Web development; 2. The rise of Vue.js as a front-end framework; 3. The complementary relationship between JS and Vue; 4. The practical application of JS and Vue.

Introduction to the method of obtaining HTTP status code in JavaScript: In front-end development, we often need to deal with the interaction with the back-end interface, and HTTP status code is a very important part of it. Understanding and obtaining HTTP status codes helps us better handle the data returned by the interface. This article will introduce how to use JavaScript to obtain HTTP status codes and provide specific code examples. 1. What is HTTP status code? HTTP status code means that when the browser initiates a request to the server, the service

Introduction to python operators Operators are special symbols or keywords used to perform operations between two or more operands. Python provides a variety of operators covering a wide range of uses, from basic mathematical operations to complex data manipulation. Mathematical operators Mathematical operators are used to perform common mathematical operations. They include: operator operation examples + addition a + b - subtraction a-b * multiplication a * b / division a / b % modulo operation (take the remainder) a % b ** power operation a ** b // integer division (discard the remainder) a//b Logical Operators Logical operators are used to concatenate Boolean values and evaluate conditions. They include: operator operations examples and logical and aandbor logical or aorbnot logical not nota comparison operations
