What is the 'double-dot' [eg. 5..toFixed()] I see in minified js? - javascript

I'm working on a project where I need to deal with javacsript frameworks for work. We have a parser that reads through them, but errors on lines with .. such as
1..toPrecision()
or
24..map(function(t){return 7..map(function(a){return e[a][t]})
It doesn't seem to understand the "..", and I don't either. Why is this valid javascript? How does mapping on a single number work? Eventually someone will fix the parser, but I'm looking for a temporary fix as to how I can edit the minified .js file to work. Is there another way to write something like 24..map()?

It's kind of a funny situation. Numbers can have a value after the decimal point, right?
console.log(1.2345); // for example
Well, it's also possible to write a number with a decimal point without any numbers following it.
console.log(5.);
So the first dot is the decimal point. The second is the property accessor.
console.log(5. .toString());
// ^ decimal point ^ property accessor
The specification defines decimal literals as:
DecimalIntegerLiteral . DecimalDigits opt ExponentPart opt
where opt means optional.

The first . is the decimal separator character. 1. is a number.
The second . is the object property accessor. someNumber.toPrecision is a function.
Another way to write it would be to write the number with more significant figures:
1.0.toPrecision()

Related

5.constructor.name - SyntaxError [duplicate]

For example,
1.toFixed(2) // Uncaught SyntaxError: Invalid or unexpected token
(1).toFixed(2) // "1.00"
let num = 1
num.toFixed(2) // "1.00"
At the same time, you don't have to wrap parenthesis around strings to call methods on them
'yo'.repeat(3) // "yoyoyo"
What is the rule at play here and where else does it apply? Guessing it has something to do with the dot being misinterpreted as a decimal for numbers?
Because the interpreter is looking for more digits (decimal values), not keywords or methods.
As others have stated, JavaScript is looking for more numbers after the decimal point. It thinks you are trying to type a float like 1.2 and it doesn't like that t there, it's not a number.
Interestingly, you can do this without parenthesis or making variable by using 2 decimal points. Like this: 1..toFixed(2). I guess you can also do 1.0.toFixed(2) if you want.
When using a variable, Javascript is confident that you're not going to add decimals after the point.
When not using a variable, Javascript thinks that you are going to add decimals after the point.
When you wrap your number with parenthesis, you say that the number is finished, and everything is fine again.
You can also use .. if you don't like parenthesis. The first one for decimals, the second one to call the method.
let num = 1;
console.log(num.toFixed(2));
// console.log(1.toFixed(2)); // ERROR
console.log((1).toFixed(2));
console.log(1..toFixed(2));

Why doesn't my function correctly replace when using some regex pattern

This is an extension of this SO question
I made a function to see if i can correctly format any number. The answers below work on tools like https://regex101.com and https://regexr.com/, but not within my function(tried in node and browser):
const
const format = (num, regex) => String(num).replace(regex, '$1')
Basically given any whole number, it should not exceed 15 significant digits. Given any decimal, it should not exceed 2 decimal points.
so...
Now
format(0.12345678901234567890, /^\d{1,13}(\.\d{1,2}|\d{0,2})$/)
returns 0.123456789012345678 instead of 0.123456789012345
but
format(0.123456789012345,/^-?(\d*\.?\d{0,2}).*/)
returns number formatted to 2 deimal points as expected.
Let me try to explain what's going on.
For the given input 0.12345678901234567890 and the regex /^\d{1,13}(\.\d{1,2}|\d{0,2})$/, let's go step by step and see what's happening.
^\d{1,13} Does indeed match the start of the string 0
(\. Now you've opened a new group, and it does match .
\d{1,2} It does find the digits 1 and 2
|\d{0,2} So this part is skipped
) So this is the end of your capture group.
$ This indicates the end of the string, but it won't match, because you've still got 345678901234567890 remaining.
Javascript returns the whole string because the match failed in the end.
Let's try removing $ at the end, to become /^\d{1,13}(\.\d{1,2}|\d{0,2})/
You'd get back ".12345678901234567890". This generates a couple of questions.
Why did the preceding 0 get removed?
Because it was not part of your matching group, enclosed with ().
Why did we not get only two decimal places, i.e. .12?
Remember that you're doing a replace. Which means that by default, the original string will be kept in place, only the parts that match will get replaced. Since 345678901234567890 was not part of the match, it was left intact. The only part that matched was 0.12.
Answer to title question: your function doesn't replace, because there's nothing to replace - the regex doesn't match anything in the string. csb's answer explains that in all details.
But that's perhaps not the answer you really need.
Now, it seems like you have an XY problem. You ask why your call to .replace() doesn't work, but .replace() is definitely not a function you should use. Role of .replace() is replacing parts of string, while you actually want to create a different string. Moreover, in the comments you suggest that your formatting is not only for presenting data to user, but you also intend to use it in some further computation. You also mention cryptocurriencies.
Let's cope with these problems one-by-one.
What to do instead of replace?
Well, just produce the string you need instead of replacing something in the string you don't like. There are some edge cases. Instead of writing all-in-one regex, just handle them one-by-one.
The following code is definitely not best possible, but it's main aim is to be simple and show exactly what is going on.
function format(n) {
const max_significant_digits = 15;
const max_precision = 2;
let digits_before_decimal_point;
if (n < 0) {
// Don't count minus sign.
digits_before_decimal_point = n.toFixed(0).length - 1;
} else {
digits_before_decimal_point = n.toFixed(0).length;
}
if (digits_before_decimal_point > max_significant_digits) {
throw new Error('No good representation for this number');
}
const available_significant_digits_for_precision =
Math.max(0, max_significant_digits - digits_before_decimal_point);
const effective_max_precision =
Math.min(max_precision, available_significant_digits_for_precision);
const with_trailing_zeroes = n.toFixed(effective_max_precision);
// I want to keep the string and change just matching part,
// so here .replace() is a proper method to use.
const withouth_trailing_zeroes = with_trailing_zeroes.replace(/\.?0*$/, '');
return withouth_trailing_zeroes;
}
So, you got the number formatted the way you want. What now?
What can you use this string for?
Well, you can display it to the user. And that's mostly it. The value was rounded to (1) represent it in a different base and (2) fit in limited precision, so it's pretty much useless for any computation. And, BTW, why would you convert it to String in the first place, if what you want is a number?
Was the value you are trying to print ever useful in the first place?
Well, that's the most serious question here. Because, you know, floating point numbers are tricky. And they are absolutely abysmal for representing money. So, most likely the number you are trying to format is already a wrong number.
What to use instead?
Fixed-point arithmetic is the most obvious answer. Works most of the time. However, it's pretty tricky in JS, where number may slip into floating-point representation almost any time. So, it's better to use decimal arithmetic library. Optionally, switch to a language that has built-in bignums and decimals, like Python.

Javascript eval - obfuscation?

I came across some eval code:
eval('[+!+[]+!+[]+!+[]+!+[]+!+[]]');
This code equals the integer 5.
What is this type of thing called? I've tried searching the web but I can't seem to figure out what this is referred to. I find this very interesting and would like to know where/how one learns how to print different things instead of just the integer 5. Letters, symbols and etc. Since I can't pin point a pattern in that code I've had 0 success taking from and adding to it to make different results.
Is this some type of obfuscation?
This type of obfuscation, eval() aside, is known as Non-alphanumeric obfuscation.
To be completely Non-alphanumeric, the eval would have to be performed by Array constructor prototypes functions and subscript notation:
[]["sort"]["constructor"]("string to be evaled");
These strings are then converted to non-alphanumeric form.
AFAIK, it was first proposed by Yosuke Hosogawa around 2009.
If you want to see it in action see this tool: http://www.jsfuck.com/
It is not considered a good type of obfuscation because it is easy to reverse back to the original source code, without even having to run the code (statically). Plus, it increases the file size tremendously.
But its an interesting form of obfuscation that explores JavaScript type coercion. To learn more about it I recommend this presentation, slide 33:
http://www.slideshare.net/auditmark/owasp-eu-tour-2013-lisbon-pedro-fortuna-protecting-java-script-source-code-using-obfuscation
That's called Non-alphanumeric JavaScript and it's possible because of JavaScript type coercion capabilities. There are actually some ways to call eval/Function without having to use alpha characters:
[]["filter"]["constructor"]('[+!+[]+!+[]+!+[]+!+[]+!+[]]')()
After you replace strings "filter" and "constructor" by non-alphanumeric representations you have your full non-alphanumeric JavaScript.
If you want to play around with this, there is a site where you can do it: http://www.jsfuck.com/.
Check this https://github.com/aemkei/jsfuck/blob/master/jsfuck.js for more examples like the following:
'a': '(false+"")[1]',
'b': '(Function("return{}")()+"")[2]',
'c': '([]["filter"]+"")[3]',
...
To get the value as 5, the expression should have been like this
+[!+[] + !+[] + !+[] + !+[] + !+[]]
Let us analyze the common elements first. !+[].
An empty array literal in JavaScript is considered as Falsy.
+ operator applied to an array literal, will try convert it to a number and since it is empty, JavaScript will evaluate it to 0.
! operator converts 0 to true.
So,
console.log(!+[]);
would print true. Now, the expression can be reduced like this
+[true + true + true + true + true]
Since true is treated as 1 in arithmetic expressions, the actual expression becomes
+[ 5 ]
The + operator tries to convert the array ([ 5 ]) to a number and which results in 5. That is why you are getting 5.
I don't know of any term used to describe this type of code, aside from "abusing eval()".
I find this very interesting and would like to know where/how one
learns how to print different things instead of just the integer 5.
Letters, symbols and etc. Since I can't pin point a pattern in that
code I've had 0 success taking from and adding to it to make different
results.
This part I can at least partially answer. The eval() you pasted relies heavily on Javascript's strange type coercion rules. There are a lot of pages on the web describing various strange consequences of the coercion rules, which you can easily search for. But I can't find any reference on type coercion with the specific goal of getting "surprising" output from things like eval(), unless you count this video by Destroy All Software (the Javascript part starts at 1:20). Most of them understandably focus on how to avoid strange bugs in your code. For your purpose, I believe the most useful things I know of are:
The ! operator will convert anything to a boolean.
The unary + operator will convert anything to a number.
The binary + operator will coerce its arguments to either numbers or strings before adding or concatenating them. Normally it will only go with strings if one or the other argument is already a string, but there are exceptions.
The bitwise operators output integers, regardless of input.
Converting to numbers is complicated. Booleans will go to 0 or 1. Strings will attempt to use parseInt(), or produce NaN if that fails. I forget the rest.
Converting an object to a string or number will invoke its "toString" or "toValue" method respectively, if one exists.
You get the idea. thefourtheye's answer walks through exactly how these rules apply to the example you gave. I'm not even going to try summarizing what happens when Dates, Functions, and Regexps are involved.
Is this some type of obfuscation?
Normally you'd simply get obfuscation for free as part of minification, so I have no idea why someone would write that in real production code (assuming that's where you found it).

Why is an integer literal followed by a dot a valid numeric literal in JavaScript?

In JavaScript it is valid to end an integer numeric literal with a dot, like so...
x = 5.;
What's the point of having this notation? Is there any reason to put the dot at the end, and if not, why is that notation allowed in the first place?
Update: Ok guys, since you mention floats and integers... We are talking about JavaScript here. There is only one number type in JavaScript which is IEEE-754.
5 and 5. have the same value, there is no difference between those two values.
I guess it is just compatibility with other C-like languages where the dot does matter.
You DO need the decimal point if you call a method on an integer:
5.toFixed(n) // throws an error
5..toFixed(n) // returns the string '5.' followed by n zeroes
If that doesn't look right, (5).toFixed(n), or 5.0.toFixed(n), will work, too.
That's a floating point number. Unlike any other language I've ever encountered, all numbers in Javascript are actually 64-bit floating numbers. Technically, there are no native integers in Javascript. See The Complete Javascript Number Reference for the full ugly story.
The correct answer in this case is, that it makes absolutely no difference.
Every number in JavaScript is already a 64bit floating point number.
The ". syntax" is only useful in cases where you can ommit the fixed part because it's 0:
.2 // Will end up as 0.2
-.5 // Will end up as -0.5
So overall it's just saving a byte, but it makes the code less readable at the same time.
What if it wouldn't be an integer, but a floating point literal?

What is the decimal separator symbol in JavaScript?

A thought struck me as I was writing a piece of JavaScript code that processed some floating point values. What is the decimal point symbol in JavaScript? Is it always .? Or is it culture-specific? And what about .toFixed() and .parseFloat()? If I'm processing a user input, it's likely to include the local culture-specific decimal separator symbol.
Ultimately I'd like to write code that supports both decimal points in user input - culture-specific and ., but I can't write such a code if I don't know what JavaScript expects.
Added: OK, Rubens Farias suggests to look at similar question which has a neat accepted answer:
function whatDecimalSeparator() {
var n = 1.1;
n = n.toLocaleString().substring(1, 2);
return n;
}
That's nice, it lets me get the locale decimal point. A step towards the solution, no doubt.
Now, the remaining part would be to determine what the behavior of .parseFloat() is. Several answers point out that for floating point literals only . is valid. Does .parseFloat() act the same way? Or might it require the local decimal separator in some browser? Are there any different methods for parsing floating point numbers as well? Should I roll out my own just-to-be-sure?
According to the specification, a DecimalLiteral is defined as:
DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt
. DecimalDigits ExponentPartopt
DecimalIntegerLiteral ExponentPartopt
and for satisfying the parseFloat argument:
Let inputString be ToString(string).
Let trimmedString be a substring of inputString consisting of the leftmost character that is not a StrWhiteSpaceChar and all characters to the right of that character.(In other words, remove leading white space.)
If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral (see 9.3.1), return NaN.
Let numberString be the longest prefix of trimmedString, which might be trimmedString itself, that satisfies the syntax of a StrDecimalLiteral.
Return the Number value for the MV
So numberString becomes the longest prefix of trimmedString that satisfies the syntax of a StrDecimalLiteral, meaning the first parseable literal string number it finds in the input. Only the . can be used to specify a floating-point number. If you're accepting inputs from different locales, use a string replace:
function parseLocalNum(num) {
return +(num.replace(",", "."));
}
The function uses the unary operator instead of parseFloat because it seems to me that you want to be strict about the input. parseFloat("1ABC") would be 1, whereas using the unary operator +"1ABC" returns NaN. This makes it MUCH easier to validate the input. Using parseFloat is just guessing that the input is in the correct format.
use:
theNumber.toLocaleString();
to get a properly formatted string with the right decimal and thousands separators
As far as I'm aware, javascript itself only knows about the . separator for decimals. At least one person whose judgement I trust on JS things concurs:
http://www.merlyn.demon.co.uk/js-maths.htm#DTS

Categories

Resources