var a=1;
b=++a*a;
console.log(b);
console.log(a);
the result is 4,2.how the program get this result?
in my mind,the result will be 2,2
can anybody tell me how the javascript compiler compile this piece of code and get the result 4,2.
Then the deep question is why these two pieces of code result are the same.
var a=2;
var b=3;
c=(a++)*a;
console.log(c);
var a=2;
var b=3;
c=(a++)*b;
console.log(c);
can anyone explain this one step by step?
++ has a higher precedence than *. Thus b = ++ a * a is evaluated as b = (++a) * a.
++a makes a equal to 2 and then a gets muliplied by itself.
On a sidenote, every time you get confused by something like this, find JavaScript's operator precedence table and try to break the equation down by yourself.
++a increases the value to 2 before the multiplication. After this, variable "a" will point to value 2 and it will make the multiplication: 2*2.
a++*a wil give you the desired result (2,2)
Related
A very simple question, but I could not find the answer anywhere. Check the following code.
var myArray = [0,1,2,3,4,5,6,7,8,9];
for(i=0; i < myArray.length; myArray++){
console.log("Loop iteration step : "+i);
}
console.log("After array increment : " + myArray);
The myArray++ is not a typo. As you can see, the code will only run once. And after running it once, the loop terminates and myArray becomes NaN.
What is happening here to the array? How can an array become a NaN?
P.S: OK, more information since everyone is curious why myArray++ is not a typo. Yes, it was a typo at first. That's how I came up with this But that's not the problem I have here. I added the complete loop because I wanted to show the place I came up with this error.
EDIT: I have fixed some (shameful) misconception in terms of what the increment operand does. I fell into the same mistake of not looking up the actual docs. I hope this helps other users not fall upon the same mistake. (thank you for pointing that out #gurvinder372.)
I highly recommend you look up the documentation for "Increment" , the first sentence explains what's happening:
The increment operator increments (adds one to) its operand and returns a value.
One would think the Increment operator ++behaves as following:
myArray++ ---> myArray = myArray + 1;
When JavaScript evaluates myArray + 1 anything can come off that. In this case just try it out:
var myArray = [0,1,2,3,4,5,6,7,8,9];
myArray + 1
"0,1,2,3,4,5,6,7,8,91"
You could assume then it assigns a string back to myArray , when increment operator in the for loop evaluates, it determines that value is not a number, hence the NaN, and for loop exits before second iteration when condition i<NaNevaluates to false. Try it out:
var a = "a";
a++;
NaN
But that's not entirely correct (I messed up in terms of what myArray++ actually does under the hood, and it's better to understand what it's actually happening). Looking at the actual specs for Postfix Increment operator, we get the following:
Steps
myArray++
lhs = myArray
oldValue = Number(myArray)
oldValue = NaN
newValue = oldValue + 1
newValue = NaN + 1
newValue = NaN
myArray = NaN
The Postfix Increment operator returns oldValue, NaN and now myArray=NaN
So what you end up with in your for loop after the first iteration when the Postfix Increment operator runs is:
for ([initialization]; [condition]; [final-expression])
statement
for ([initialization]; i<myArray.length; NaN)
statement
for ([initialization]; i<NaN.length; NaN)
statement
for ([initialization]; i<undefined; NaN)
statement
for ([initialization]; false; NaN)
statement
I hope this helps clear up a bit what's happening in every step and part of the loop and why myArray ends up with value NaN.
Here's something interesting to try and see if you understand why in this infinite loop your myArraygets to stay as [...] but counter is NaN after second call.
var myArray = [1,2,3,4,5,6,7,8,9];
var counter = myArray;
for(let i=0; i<myArray.length; counter++){
console.log("Infinite calls. Never leaving and counter is " + counter);
// i++; if you don't want to eat up that infinite loop.
}
Answer
You get the infinite loops because your expression i<myArray.length will always evaluate to True since i is never modified. Meanwhile, counter will go to NaNafter first iteration because of what was explained at the start of the post. myArray stays cool because the Postfix Increment is done upon counter.
Why does this loop iterate but the one you did, does not? Because in the one you did you end up changing the value of myArrayinto NaNforcing the expression in the loop i<NaN.length---> i<undefined to be false after first iteration, causing the loop to exit.
As per spec for Postfix Increment Operator
Let oldValue be ToNumber(GetValue(lhs)).
And
var myArray = [0,1,2,3,4,5,6,7,8,9];
Number(myArray) //NaN
Hence myArray++ => NaN
Demo
var myArray = [0,1,2,3,4,5,6,7,8,9];
console.log( "Just increment using postfix operator ", myArray++ );
myArray = [0,1,2,3,4,5,6,7,8,9];
console.log( "Number conversion ", Number(myArray) );
When you do ++ and if the variable is not of type number, it will be converted to string using toString and then converted to number.
Object.toString returns [object Object], so Number('[object Object]') returns NaN
Also when you do ++ is a short hand for += so myArray++ is equal to myArray = myArray + 1;. Now that your myArray is not an array, it does not have property length and it returns undefined (as everything in JS is an object) and the loop breaks.
As rightly pointed out by #barmar, Array.toString returns array.join. So it is equal to Number("0,1,2..."). Since comma(,) is not a valid numeric character, it returns NaN. Also, when value is compared to NaN, it returns false hence breaking the loop.
Sample:
var myArray = [0,1,2,3,4,5,6,7,8,9];
console.log(myArray.toString())
console.log(Number(myArray.toString()))
console.log(1<NaN)
I was reading David Flanagan's JavaScript: The Definitive Guide, probably the fattest book for JavaScript in the world. When briefly describing array initializers, Flanagan said "The element expressions in an array initializer are evaluated each time the array initializer
is evaluated". What does this means. My practice results made me more confused:
var a = 50;
var b = 70;
var array = [a+b, 50];
console.log (array [0]); //120
a = 60;
console.log (array [0]); //120
var other = array;
console.log (other [0]); //120
I thought the result would be 130 after I change a's value to 60, because the expression is going to be re-evaluated. But it's not that. I know I am completely getting it wrong. Can someone explain what Flanagan is trying to explain in that sentence?
He means that when the array literal expression is ("re"-)evaluated, so will be its contents.
function makeArray() {
return [a];
}
var a = 0;
console.log(makeArray()); // [0]
a = 1;
console.log(makeArray()); // [1]
So, nothing special actually, just default expression behaviour.
You've misquoted the author; what he actually said is
The element expressions in an array initializer are evaluated each time the array initializer is evaluated.
Rather than the term "array initializer", it would be clearer, and more in line with common usage, if he said "array literal". If we adopt the common-sense interpretation of "array initializers" as meaning "initializers for an array-valued variable", then such initializers could be array literals, but could also be any array expression. (Having said that, it does appear that the spec uses the term "array initializer" for "array literal" in Section 12.2.5, so the author's usage is not wrong in that technical sense.) Array literals (basically, anything of the form [...]) can, on the other hand, be used as initializers, but can also be used elsewhere.
What he appears to be trying to say is that an array literal such as
[a]
re-evaluates a each time it itself is re-evaluated, such as when a function is re-executed. If you think about it, that's pretty obvious. It's hard to see how it could work any other way. So the function
function foo(x) { return [x]; }
will return the array [1] when called as foo(1), and the array [2] when called as foo(2), because the array literal [x] is re-evaluated each time the function is called.
This is an entirely different issue from the one that is tripping you up, which is that
var a = 22;
var b = [a];
a = 42;
console.log(b);
does not change b to have the value [42]. This behavior has nothing to do with how array initializers are (re-)evaluated or their component elements are (re-)evaluated. Is has to do with how JavaScript variables and references work. The above would change the value of b if b were storing a dynamic reference to a as its element, but JavaScript has no such notion of dynamically-updatable references. To put it a different way, the console.log(b) line is indeed evaluating b, but that just returns whatever b already is. It does not (re-)evaluate the expression [a] originally used to set b. The fact that b happens to have taken on he value resulting from evaluating [a] is lost immediately after the statement setting the value of b, at which point b now has the value [22].
Consider also the following example, which is completely analogous:
var a = 1, b = 2, c = a + b;
a = 42;
console.log(c);
Here, no-one would expect the expression given as the initial value for c to change when the value of a changes later. c is 3, and it will always be until explicitly re-assigned. In the console(c) line, yes, we are "evaluating" c, but that is merely a matter of retrieving the value of c, not of re-evaluating some expression which happens to have used to assign a value to c in the past. There are some other declarative-style language paradigms where things might behave in that way, but not JavaScript.
Here you assigning the array to array variable and it will store that value until that variable(unless you modify that variable) goes out of scope. In the second statement you're reusing the the same array pointed to by "array" variable. Third statement is just assigning the reference to "array" variable to another variable and access the same element.
Only the first time a+b statement is evaluated and that resulting array is saved as value reference. Last statement is an example of pass by value(Javascript is always pass by value) where copy of "array" variable is created as "other", and "other" also points to same memory reference pointed by "array" variable.
Consider the following bit of code:
f=(m,c)=>{m?c()&f(--m,c):0}
(thanks to zzzzBov for this little nugget)
which is a "for"-less loop
and the following:
a=b=>b+1
Given these two snippets, and the fact that:
z = 0; f(10,a(z));
which I would expect would result in z equating to 10, but instead returns in the JavaScript console the following "TypeError: c is not a function", how would one go about altering this code to ensure that the loop goes ahead, without having to resort to a while or for loop?
I'm asking this as a matter of education purposes... Hopefully I can get some insight into what can be done...
The function f is taking 2 arguments: m, the number to iterate, and c, the function to be called m times. This means that the second argument, c should be a function. For example:
f=(m,c)=>{m?c()&f(--m,c):0}
f(15, function() {
console.log("Hello")
})
This will iterate through the c function 15 times, calling console.log 15 times.
Of course, to achieve what you wanted in the second bit, you could use this:
z=0, f(10,()=>z++)
This would be a regular arrow function to increase z by 1
Take a look at the code on babel
Hope I could help!
It sounds you are looking for a folding function (like array reduce), not a simple "looping" function that only executes side effects. With that current function, which desugars f(5, c) to effectively c(); c(); c(); c(); c(); you would need to do
let z = 0;
f(10,()=>{ z = a(z) });
If however you want to make a function that repeatedly applies a function, like a(a(a(a(a(…))))), you would need to write
let times = (n, f, s) => n>0 ? times(n-1, f, f(s)) : s;
so that you can do
let a = b=>b+2
times(5, a, 0) // 10
Let's say I'm declaring a list of variables in the following manner:
var a = "value_1"
, b = "value_2"
, c = b;
What is the expected value of c? In other words, is the scope of a variable immediately available after the comma, or not until the semicolon?
This is as opposed to the following code snippet, where it is very clear that the value of c will be "value_2":
var a = "value_1";
var b = "value_2";
var c = b;
I thought I'd ask rather than test in a browser and just assume that the behavior will be consistent.
See the comma operator:
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand
So b = "value_2" is evaluated before c = b
It's not really an answer to the question, but when faced with such a choice between two expressions of the same thing, always choose the one which is the less ambiguous.
In your second code snippet, it's clear to everybody what the final state is. With the first one, well, you had to ask a question here to know :) If you come back to the code in a month from now, or if somebody else does, then you'll have to go through the same process of finding out the actual meaning. I don't think it's worth the 6 characters you're saving.
Take the following javascript:
var x = (p) ? 1 : 0;
p can be any value. It there any situation the parenthesis can have effect?
If so: please provide examples.
This is a bit of a contrived example, but hey, why not?
var y = -2;
var x = (y+=2)?0:1?1:0;
alert(x); // will alert '1'
versus
var y = -2;
var x = y+=2?0:1?1:0;
alert(x); // will alert '-2'
Check out this Javascript precedence table: http://www.codehouse.com/javascript/precedence/. Anything below the ternary operator (e.g. "?:") is going to require parentheses if you use it in ternary operator's evaluated expression.
In case p was divided into several boolean expressions with different operators, nested parenthesis can decide the order of how to expressions are computed. But I have the feeling you already know that, and it was not part of the question.
But no, parenthesis have no effect on p as a whole. And I don't know why would someone put them, for I don't think they improve readability.
I can't think of any reason you would need parenthesis there except for readability.
No. It's sometimes done by analogy with:
if (p)
where the brackets are compulsory.