Algorithm for javascript pre-defined functions (parseInt, parseFloat, isNaN, etc.) - javascript

What is the best way, if even possible, to see the underlying code for the predefined functions in Javascript. Is there documentation that shows how these were coded, or an easy way to actually view the underlying code?
parseInt
parseFloat
isNaN

They are native functions, and maybe coded in the language your JS engine was written in - you'd need to contact it's source.
However, you probably are more interested in the EcmaScript specification that describes how the algorithms work.
And if you're lucky, for some of the functions you even might find an JS equivalent. You'll find them mostly on pages that test ES implementations against the standard.

After looking further I found this in the ECMAScript specification.
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
When the parseInt function is called, the following steps are taken:
Let inputString be ToString(string).
Let S be a newly created substring of inputString consisting of the first character that is not a
StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
space.) If inputString does not contain any such characters, let S be the empty string.
Let sign be 1.
If S is not empty and the first character of S is a minus sign -, let sign be 1.
If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character
from S.
Let R = ToInt32(radix).
Let stripPrefix be true.
If R  0, then© Ecma International 2011 105
a. If R < 2 or R > 36, then return NaN.
b. If R  16, let stripPrefix be false.
Else, R = 0
a. Let R = 10.
If stripPrefix is true, then
a. If the length of S is at least 2 and the first two characters of S are either ―0x‖ or ―0X‖, then remove
the first two characters from S and let R = 16.
If S contains any character that is not a radix-R digit, then let Z be the substring of S consisting of all
characters before the first such character; otherwise, let Z be S.
If Z is empty, return NaN.
Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20
significant digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the
implementation; and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent
approximation to the mathematical integer value that is represented by Z in radix-R notation.)
Let number be the Number value for mathInt.
Return sign  number.
NOTE parseInt may interpret only a leading portion of string as an integer value; it ignores any characters that
cannot be interpreted as part of the notation of an integer, and no indication is given that any such characters were
ignored.
When the parseFloat function is called, the following steps are taken:
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 inputString does not contain any such characters, let trimmedString be the empty string.
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 of numberString.
NOTE parseFloat may interpret only a leading portion of string as a Number value; it ignores any characters that
cannot be interpreted as part of the notation of an decimal literal, and no indication is given that any such characters were
ignored.
Returns true if the argument coerces to NaN, and otherwise returns false.
If ToNumber(number) is NaN, return true.
Otherwise, return false.
NOTE A reliable way for ECMAScript code to test if a value X is a NaN is an expression of the form X !== X. The
result will be true if and only if X is a NaN.

Those functions are implementation specific depending on browser, and are not written in JS (unless somebody's decided to write a browser engine in JS). The code is not guaranteed to be the same across environments, though they do have to (in theory) adhere to the ECMAScript specification for their behavior.

Related

Why do trailing and leading zeros cause my function to return values i do not want?

This set of code i am providing should take any number i enter and reverse it. Currently the function works when n = 21.365 or n = 5698 but when n = 0456456456 it returns 41422397 instead of 6546546540 or when n = 056985 it returns 58965 instead of 589650 and when n = 016540 it returns 257 instead of 45610.
This is what i have written so far
//rules & limitations
//negative numbers should remain negative
//leading zeros should be removed
//the function can accept floats or integers
//the function will return integers as integers
function reverseNumberWithBuiltInFunctions(n) {
return (
parseFloat (
n
//convert the number to a string
.toString()
//convert to array of characters
.split('')
//reverse array of characters
.reverse()
//join reversed array of characters
.join('')
) * Math.sign(n)
)
}
I would like if n = 001 then 100 is returned or if n = 0456456456 then 6546546540 is returned. Essentially i am having trouble when leading or trailing zeros or both are included in "n" or it seems like issues arise when there is some sort of pattern to the numbers.
Also, why is it that when n = 016540 it returns 257?
Do you know of any solutions that could help improve the logic of the function with the given rules and limitations that would yield the desired results?
What you want is impossible if the inputs are integers or floats. There is no such thing as "leading zeros" on either integers or floats. If you use leading zeros to make a integer literal, it becomes an octal literal (changing the value; that's why n = 0456456456 behaves the way it does, 0456456456 is just the octal way to spell 79322414). If you parse a string with leading zeros to make an integer, they're simply ignored (parseInt('000123') produces the same value as parseInt('123'), namely, the value 123). That's why 016540 becomes 257: the octal literal is equivalent to the decimal literal 7520, and reversing it and parsing back to integer ignores the leading 0, leaving 257.
You can't preserve such leading zeros because they don't exist outside of string form. And you'll lose the trailing zeros on reversal because they become leading zeros in the new form.
Either work with strings exclusively, or accept that you'll lose leading zeros.
I'll note that your own rules in the comments specify:
//leading zeros should be removed
so it's working as expected here.
You have to pass it in as a string as leading 0's in your numbers will not be interpreted as such.
For example:
// Will always be evaluated as 1
let foo = 001;
console.log(foo);
If you were to supply n as a string, you may do it like this:
reverseNumberWithBuiltInFunctions = n => parseFloat(n.toString().split('').reverse().join(''));
console.log(reverseNumberWithBuiltInFunctions('0456456456'))
console.log(reverseNumberWithBuiltInFunctions('056985'))

Why does passing '1.0' to a function change it to '1' in javascript

Can someone explain to me why when pass 1.0 to a function in javascript it gets converted to 1 and how to work around this quirk?
var return_me = function(value) {
return value;
}
console.log("1.0 is returned as " + return_me(1.0));
JavaScript doesn't distinguish between int or float like other more strongly typed languages. It just has one Number type. From the ECMA specifications:
Once the exact mathematical value (MV) for a numeric literal has been determined, it is
then rounded to a value of the Number type. If the MV is 0, then the
rounded value is +0; otherwise, the rounded value must be the Number
value for the MV (as specified in 8.5), unless the literal is a
DecimalLiteral and the literal has more than 20 significant digits, in
which case the Number value may be either the Number value for the MV
of a literal produced by replacing each significant digit after the
20th with a 0 digit or the Number value for the MV of a literal
produced by replacing each significant digit after the 20th with a 0
digit and then incrementing the literal at the 20th significant digit
position. A digit is significant if it is not part of an ExponentPart
and
it is not 0;
or there is a nonzero digit to its left and there is a nonzero digit, not in the ExponentPart, to its right.
A conforming
implementation, when processing strict mode code (see 10.1.1), must
not extend the syntax of NumericLiteral to include OctalIntegerLiteral
as described in B.1.1.
More info on Number.
So basically, the answer is that JavaScript will display numbers that look like integers as integers and numbers that look like floats as floats.
In javascript there are six build in types of values.
string
number
boolean
null and undefined
object
symbol
These are mentioned to the book You don't know JS which I find really useful in my effort to learn javascript.
As a result js sees the var value of your function as a typeof number and understands that 1.0 is the same as 1. (in case the 1.0 was 1.9 it returns 1.9 as expected).
Now if you want to keep these decimals (even if there are zero digits) you could pass the value as a string.
console.log("1.0 is returned as " + return_me("1.0"));

parseInt() parses number literals with exponent incorrectly

I have just observed that the parseInt function doesn't take care about the decimals in case of integers (numbers containing the e character).
Let's take an example: -3.67394039744206e-15
> parseInt(-3.67394039744206e-15)
-3
> -3.67394039744206e-15.toFixed(19)
-3.6739e-15
> -3.67394039744206e-15.toFixed(2)
-0
> Math.round(-3.67394039744206e-15)
0
I expected that the parseInt will also return 0. What's going on at lower level? Why does parseInt return 3 in this case (some snippets from the source code would be appreciated)?
In this example I'm using node v0.12.1, but I expect same to happen in browser and other JavaScript engines.
I think the reason is parseInt converts the passed value to string by calling ToString which will return "-3.67394039744206e-15", then parses it so it will consider -3 and will return it.
The mdn documentation
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN
parseInt(-3.67394039744206e-15) === -3
The parseInt function expects a string as the first argument. JavaScript will call toString method behind the scene if the argument is not a string. So the expression is evaluated as follows:
(-3.67394039744206e-15).toString()
// "-3.67394039744206e-15"
parseInt("-3.67394039744206e-15")
// -3
-3.67394039744206e-15.toFixed(19) === -3.6739e-15
This expression is parsed as:
Unary - operator
The number literal 3.67394039744206e-15
.toFixed() -- property accessor, property name and function invocation
The way number literals are parsed is described here. Interestingly, +/- are not part of the number literal. So we have:
// property accessor has higher precedence than unary - operator
3.67394039744206e-15.toFixed(19)
// "0.0000000000000036739"
-"0.0000000000000036739"
// -3.6739e-15
Likewise for -3.67394039744206e-15.toFixed(2):
3.67394039744206e-15.toFixed(2)
// "0.00"
-"0.00"
// -0
If the parsed string (stripped of +/- sign) contains any character that is not a radix digit (10 in your case), then a substring is created containing all the other characters before such character discarding those unrecognized characters.
In the case of -3.67394039744206e-15, the conversion starts and the radix is determined as base 10 -> The conversion happens till it encounters '.' which is not a valid character in base 10 - Thus, effectively, the conversion happens for 3 which gives the value 3 and then the sign is applied, thus -3.
For implementation logic - http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.2
More Examples -
alert(parseInt("2711e2", 16));
alert(parseInt("2711e2", 10));
TO note:
The radix starts out at base 10.
If the first character is a '0', it switches to base 8.
If the next character is an 'x', it switches to base 16.
It tries to parse strings to integers. My suspicion is that your floats are first getting casted to strings. Then rather than parsing the whole value then rounding, it uses a character by character parsing function and will stop when it gets to the first decimal point ignoring any decimal places or exponents.
Some examples here http://www.w3schools.com/jsref/jsref_parseint.asp
parseInt has the purpose of parsing a string and not a number:
The parseInt() function parses a string argument and returns an
integer of the specified radix (the base in mathematical numeral
systems).
And parseInt calls the function ToString wherein all the non numerical characters are ignored.
You can use Math.round, which also parses strings, and rounds a number to the nearest integer:
Math.round("12.2e-2") === 0 //true
Math.round("12.2e-2") may round up or down based on the value. Hence may cause issues.
new Number("3.2343e-10").toFixed(0) may solve the issue.
Looks like you try to calculate using parseFloat, this will give you the correct answer.
parseInt as it says, returns an integer, whereas parseFloat returns a floating-point number or exponential number:
parseInt(-3.67394039744206e-15) = -3
parseFloat(-3.67394039744206e-15) = -3.67394039744206e-15
console.log('parseInt(-3.67394039744206e-15) = ' , parseInt(-3.67394039744206e-15));
console.log('parseFloat(-3.67394039744206e-15) = ',parseFloat(-3.67394039744206e-15));

How does the Javascript '>' operator compare characters with a space?

I am trying to understand this expression:
((ch = stream.getChar()) > ' ')
Here, getChar() gets a character. How does this greater-than comparision operator check if any char is greater than an empty space?
Is this possible?
An empty space has a character code. Even though it doesn't look like much, it still has a value. So does the character taken from the stream. Comparing the character codes of these values is what produces the output.
Let's take a gander at the language specification (the algorithm itself is described in here) (do note that it defines <, but the > operator simply flips the resulting value).
What the operator does is try to convert both operands to primitive types, with a preference for numbers:
2. a. Let py be the result of calling ToPrimitive(y, hint Number).
2. b. Let px be the result of calling ToPrimitive(x, hint Number).
In our case, x === stream.getChar() and y === ' '. Since both of the operands are primitive strings already, that results in the original values (px = x, py = y), and we move on to:
4. Else, both px and py are Strings
Now it does checks to see if any of the operands are prefixes of the other, for example:
'abc' > 'abcd' // false
'foo' > 'foobar' // false
Which is relevant if getChar() results in a space, since the space is a prefix of itself:
' ' > ' ' // false
We move on, to finding the first character in x and y who're on the same position in the strings, but are different characters:
Let k be the smallest nonnegative integer such that the character at position k within px is different from the character at position k within py. (There must be such a k, for neither String is a prefix of the other.)
(e.g., 'efg' and 'efh', we want g and h)
The characters we've found are then converted to their integer values:
Let m be the integer that is the code unit value for the character at position k within px.
Let n be the integer that is the code unit value for the character at position k within py.
And finally, a comparison is made:
If m < n, return true. Otherwise, return false.
And that's how it's compared to the space.
tl;dr It converts both arguments to their code-unit integer representations, and compares that.
In Javascript strings are compared in alphabetical order. These expressions are true:
'abacus' <= 'calculator'
'abacus' < 'abate'
In most (if not all) programming languages, characters are represented internally by a number. When you do equality/greater-than/less-than checks what you're actually checking is the underlying number.
hence in JS:
alert('c' > 'b'); // alerts true
alert('a' > 'b'); // alerts false
A space character also has a numeric representation, therefore the check is a valid one.
[string] > [string] will compare the character(s) by their representative values (see ASCII Table)
Characters are stored in the computer's memory as a number (usually a byte or two).
Each character has a unique identifying number.
By checking if a character is greater than space, you actually comapare their place in a table.
See http://en.wikipedia.org/wiki/ASCII for more.
Check out this link, it'll explain how the comparison works on JS: http://javascript.about.com/od/decisionmaking/a/des02.htm
Basically, you're comparing the ASCII value of each character to the ASCII value of the blank space, which is also, a character and therefore, has a corresponding ASCII value.

Javascript Checking for NaN - Results not as expected

I have an application that reads in a number via ajax, the number is hexadecimal and I parse it and convert to decimal.
The numbers come in through a wireless serial link and are not 100% reliable so I need to check them before I start processing the data. The numbers take the form ****025781610403e5**** for example. The **** is just a way of checking the start and end of the number that I have used in the past with non web based projects and could be changed.
Anyway to my question at last: As part of error checking I thought I would check for NaN as I do get NaN errors when I have been testing but while *1234 gives a positive NaN 12**34 does not, why is that? and what else can I do to test?
Here is some of the code I have used, please note I am fairly new to javascript.
function readSliceConvert()
{
functionReadForm()
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML=testVal;
testNum1 = h2d(testVal)
document.getElementById("battDb5").innerHTML=testNum1.toString();
testNum2 = parseInt(testVal);
document.getElementById("battDb6").innerHTML=testNum2.toString();
if (isNaN(testNum2))
{
errorCount++;
document.getElementById("battDb3").innerHTML=errorCount.toString();
document.getElementById("battDb4").innerHTML=testVal;
return;
}
}
That's because you are using parseInt, it will silently ignore characters at the end of the string when there are some digit in the beginning of the string that it can parse.
I don't know what your h2d function is doing, but it seems that you are converting the hexadecimal string to a number, then to a string in decimal form, then back to a number. I don't see any reason why the output of parsing the hexadecimal string couldn't be a number.
For example like this, returning null if the parsing fails:
function h2i(str) {
var num = 0;
var digits = "0123456789abcdef";
str = str.toLowerCase();
for (var i = 0; i < str.length; i++) {
var n = digits.indexOf(str.substr(i, 1));
if (n == -1) return null;
num = num * 16 + n;
}
return num;
}
Demo: http://jsfiddle.net/Guffa/6yAaP/
Usage:
testVal = hexString.slice(4,18);
document.getElementById("battDb4").innerHTML = testVal;
testNum = h2i(testVal)
document.getElementById("battDb5").innerHTML = testNum.toString();
if (testNum == null)
{
errorCount++;
document.getElementById("battDb3").innerHTML = errorCount.toString();
document.getElementById("battDb4").innerHTML = testVal;
return;
}
Do you know what parseInt() does?
From MDN
parseInt is a top-level function and is not associated with any
object.
The parseInt function converts its first argument to a string, parses
it, and returns an integer or NaN. If not NaN, the returned value will
be the decimal integer representation of the first argument taken as a
number in the specified radix (base). For example, a radix of 10
indicates to convert from a decimal number, 8 octal, 16 hexadecimal,
and so on. For radices above 10, the letters of the alphabet indicate
numerals greater than 9. For example, for hexadecimal numbers (base
16), A through F are used.
If parseInt encounters a character that is not a numeral in the
specified radix, it ignores it and all succeeding characters and
returns the integer value parsed up to that point. parseInt truncates
numbers to integer values. Leading and trailing spaces are allowed.
Run the code in the console
console.log( parseInt("12**34",10) );
So you are running isNaN against a number since parseInt returns 12.
When you have the * as the first character, there are no leading numbers to return.
console.log( parseInt("*1234",10) );
You're seeing weird behaviour because isNan is broken (see the mozilla docs for details).
A better way to test your data is correctly formatted would be a quick regular expression, like serial.test(/^\d+$/), which will succeed if the entire serial is entirely numeric, or serial.test(/^\*{4}\d+\*{4}$/) which will succeed if the serial is four asterisks, followed by one or more number, followed by another four asterisks.
Update: #Guffa's answer is correct, and should be accepted, but I'll leave this here as I think there's a valid argument in the bigger picture that you could better accomplish what you're trying to do with a regular expression.
Running test on the string executes the supplied regular expression, and returns true if it matches the string.
Regular expressions are just patterns describing text, which can be incredibly complex or as simple as the example I've given (\d+ means match a number (\d) one or more times (+), with anchors for the beginning (^) and end ($) of the string to indicate that we want to match the whole string, not just part of it. They're ridiculously useful, so it's almost certainly worth taking the time to learn the basics of how they work, and expand you knowledge over time. There's a great tutorial on regular-expressions.info that'll get you started in no time.

Categories