Bitshift Operator Used on Object in Javascript - javascript

I've been trying to teach myself Javascript lately and I'm noticing several slightly quirky syntax choices used by various different authors. Usually I can figure them out, but this one's stumped me a bit.
The author of the post here creates an empty object, colors, which will contain a set of properties for each background color in the page. Each color property will have a value equal to the total area covered by that color. To do this, he uses the following syntax:
// ...set or override it in the colors object,
// adding the current element area to the
// existing value.
colors[bgColor] = (colors[bgColor] >> 0) + nodeArea;
At this point, the property named by the value of bgColor may or may not be present in the object. The intent of the expression in the parenthesis is presumably to return the running total or 0 if this is the first time the color is seen. My question is, is this the right shift operator being overloaded and I'm searching for the wrong name, or why does the right shift behave this way?

The intent of the expression in the parenthesis is presumably to return the running total or 0 if this is the first time the color is seen. My question is, is this the right shift operator being overloaded and I'm searching for the wrong name, or why does the right shift behave this way?
It's not overloaded (JavaScript doesn't have operator overloading). It's relying on the fact that undefined >> 0 is 0 and anyNumber >> 0 is anyNumber (caveats to follow). If the property doesn't exist yet, looking it up yields undefined, and so >> 0 turns that into 0. If the property is defined and contains a whole number that fits in 32 bits, >> 0 returns the number without changing it. (If the number has a fractional part, it's truncated, and if it doesn't fit in 32 bits, it's wrapped if I'm reading that right, but I don't think that's what the coder is trying to do.) So by doing that, then adding the area, they are indeed adding to a running total (or initializing it if it isn't there yet).
It's mostly a shorthand version of:
if (colors[bgColor]) {
colors[bgColor] += nodeArea;
}
else {
colors[bgColor] = nodeArea;
}
...(as any falsey value >> 0 is 0) but with the added feature that it will always result in a non-NaN number provided nodeArea is a non-NaN number, whereas with some truthy non-number values for colors[bgColor] ({}, for instance), the "long" version above would result in a string or in NaN.

It is just one of the tricks to avoid an if condition. When you create the property with the value in bgColor, you might do something like this
if (colors[bgColor] === undefined) {
colors[bgColor] = 0;
}
colors[bgColor] += nodeArea;
This is is to make sure that the initial value is 0, if the bgColor is not there in colors, otherwise undefined will be the value. So, to avoid that, if we can convert undefined to 0 we can simply avoid that if condition.
console.log(undefined >> 0);
# 0
So, colors[bgColor] >> 0 will be 0 if bgColor is not already defined, otherwise the actual value as it is, since right shifting by zero doesn't change the actual value.

It might be an attempt to cast the color value as a 32-bit value, since Javascript normally stores all values as IIRC 64-bit floats (with 53 bit precision), but on bitwise operations it treats them as 32-bit integers. This might be an attempt to force the value to be treated as such before adding NodeArea.
I think it also forces it to be interpreted as a Number, but the implicit type of NodeArea would have that effect as well, normally.
edit - T.J. Crowder also makes another point which I tried to find from MDN but didn't: the return value of the operation if the property doesn't exist would be 0, thus setting the value as well). In face his whole post makes a good point :P.

Related

Why does the divide portion make the outshow as NaN

my code below works to add all the values together and displays the total, when I try an divide the items (/ val.flowers) it outputs NaN.
trimPerFlowerA(){
let lineA = this.model.processed.filter(val => val.originatingLine === 'A');
if(lineA.length > 0)
return lineA.map(val => {
return (val.trimA+val.trimB+val.trimC+val.flowerOilGrade/val.flowers)
}).reduce((a,b) => a+b,0);
return 0;
}
If I were to place a bet, I would say that you have some undefined lurking around.
This problem really depends on your input data and therefore on the contents of this.model.processed.
On a general basis, a number of calculations in JavaScript can result in NaN.
Some typical cases are:
"A"/0
"A"/"B"
0/"A"
0/0
NaN/0
0/NaN
NaN/NaN
undefined/10
1/undefined
However, in your specific case it's also possible that the problem is not in the division but in the sum within the (val.trimA+val.trimB+val.trimC+val.flowerOilGrade/val.flowers) expression.
In particular, you can have NaN also for:
NaN+1/10
undefined+1
And all similar expressions.
I would recommend putting some breakpoints around and verify the individual values. If the amount of entries doesn't lend itself to breakpoints, try and put some console.log on those same values and then check them. This should allow you to pinpoint the specific value (or values) that cause the output to be NaN.
Also, once you found the issue, you will probably want to cover your base by adding unit tests working against both valid and invalid input data.

Storing different NaN value in variable

I figured there was nothing preventing code from storing a NaN-value different from the global NaN in a variable. However, i quickly experienced that this was dependent on the browser. Storing such a value in a variable worked just fine in Chrome (Version 67.0.3396.99 (Official Build) (64-bit)), while it did not in Firefox (61.0.1 (64-bit)).
Is behavior regarding this not clear from the spec, or does FF not fully follow it here? Why does FF convert the number to the value of the global NaN?
Here is a related snippet for testing:
let buffer = new ArrayBuffer(8);
let float = new Float64Array(buffer);
let bytes = new Uint8Array(buffer);
float[0] = NaN
bytes[0] = 1;
let differentNaN = float[0];
float[0] = differentNaN;
console.log(`We are ${bytes[0] === 0 ? "not" : "potentially"} on chrome!`);
6.1.6 The Number Type explains this fully:
[...] except that the 9007199254740990 (that is, 253-2) distinct
“Not-a-Number” values of the IEEE Standard are represented in
ECMAScript as a single special NaN value. (Note that the NaN value is
produced by the program expression NaN.) In some implementations,
external code might be able to detect a difference between various
Not-a-Number values, but such behaviour is implementation-dependent;
to ECMAScript code, all NaN values are indistinguishable from each
other.
along with the below
Note
The bit pattern that might be observed in an ArrayBuffer (see 24.1) or
a SharedArrayBuffer (see 24.2) after a Number value has been stored
into it is not necessarily the same as the internal representation of
that Number value used by the ECMAScript implementation.
I knew i had seen something like this in the spec before, but somehow didn't find it in my research before posting the question, and still took 40 minutes to find it after posting (i must be blind).

while(i) loop in JavaScript

I ran the below code in JavaScript
let i = 3;
while (i) {
console.log(i--);
}
since the while(i) is not like while(i>0) then I expected the result as 3,2,1,0,-1,-2,...
but the actual result is 3,2,1. Could anyone explain this case to me? I am confused.
The while loop runs until the check condition is false.
In this case, it is the value of i.
Since Javascript is dynamically typed(ie - we don't define the types when defining the variables) the value of i is converted into a boolean from the type it is currently in.
In this case, you are setting numerical values to i. And the number 0 is considered to be falsely. Therefore, breaking the while loop.
You can refer here for a full list of falsely value.
While loops run until its condition is set false. Note that all statements such as while, if and ternaries all handle conditions in the same way. To have a better understanding on how the simplest and quickest way is to test them with ternaries.
I usually run something such as the following on a js console such as chrome (ctrl + j)
1?2:3;
0?2:3;
5?2:3;
"Hello"?2:3;
""?2:3;
And so on. These are conditional statements, the first number is taken as a condition, the second (2) is what will be returned if it were true, and the third (3) is what it will return if it were false. Note that 2 and 3 are just random numbers.
In the example you have shown, i is an integer. For an integer, only 0 is taken as a false.

Is it ever possible to define the square root of a negative number in JavaScript?

I am making a thing that's just like the built-in Math in JavaScript, but it has other features like factorial, gamma function, summation, etc. I'm planning on doing imaginary numbers, like square root of negative 1.
When I saw that -1^0.5 (square root when raising a number to the half power) is equal to NaN. A lot of things are equal to NaN though, like 1-"a", or 1÷0, etc. Here is (a portion of) my code:
/*What I'm Thinking*/
foo {
...
pow: function(x, y){ // maybe?
...
}
I: "i", // Probably not the efficient way
I2: -1 // ...
// and more crazy ideas
}
I was even thinking of doing a function to do it. My last idea was another pow function, and when the base is negative, it won't give up and maybe return "i" or something; but once again, strings are probably not the most efficient way because of addition, subtraction, multiplication, division, etc. which is the hard part.
Is there any other better method to making imaginary numbers, or at least any that would help, or is this technically impossible in JavaScript?
You have to consider two modes that both have advantages and disadvantages that have a balance that depends on the actual situation.
In the real numbers mode, the pow function has, if at all (i.e., the basis is non-negative), a unique result that obeys the usual power laws like a^(b+c)=a^b*a^c, (a*b)^c=a^c*b^c and a^(b*c) = (a^b)^c.
In the complex numbers mode, the pow function has almost always a result. However, the defining relations/ equations will then also almost always have multiple solutions that could equally well be the values of this function. For rational exponents one may think of set-valued results, the roots of a polynomial equation. For irrational or even complex exponents the results exist just by continuity without intrinsic meaning.
The usual way to allow for both modes is to have a complex data type such that only on arguments of this data type the complex version of pow is used. As operator overloading does not exist in javascript, you can not have a complex data type where c=a*b is syntactically correct, you have to use syntax like c=a.mul(b) or c=Complex.mul(a,b).
You could pass an object that resolves itself to values when used in math operations:
var I={
toString:_=>"I",
valueOf:_=>NaN,
pow:_=>I
}
usecases:
console.log(I*2);//NaN
console.log(I+" is a string now");
console.log(I.pow(5));
Implemented in Math.pow:
var temp=Math.pow
Math.pow=function(a,b){
return temp(a,b) || I;
}
Number.prototype.pow=function(a){ return Math.pow(this,a);};
console.log(
Math.pow(5,2),
Math.pow(-1,0.5),//I
Math.pow(5,2).pow(2),
Math.pow(-1,0.5).pow(5)//I
);

AE JavaScript finding Layer Object when none is given

Attempting to create a 3D shape with children that rotates at an accelerating pace from 0 to 3 seconds, I used the following script
if (time < 3)
Math.pow(time, 2)*30;
That gave me the following error
After Effects warning: Object of type Layer found where a Number,
Array, or Property is needed
Expression disabled.
Error occured at line 0.
Comp: 'Main'
Layer: 15 ('Blue')
Property: 'Y Rotation'
Comp name, layer name and property name are all valid. They point to the property I was trying to edit.
However, what puzzles me is that I fixed that by using the following code.
ctime = time;
if (ctime < 3)
Math.pow(ctime, 2)*30;
The code is now working as intended, and I have no idea why.
If the condition is false, the two would be different since there would be no last statement to use.Try: (time < 3)?Math.pow(time, 2)*30:time;
Math.pow(time^2*30); is simply bad code. Math.pow expects two arguments and you only gave it one. Also ^ is a bitwise operator, there is no power raising operator in JavaScript, you need to use Math.pow.

Categories

Resources