I saw this way to execute the code:
[eval][0]('alert("hello")')
I want to know what does unquoted 'eval' surrounded by square brackets mean and why this works. (For example, window['eval'][0]('alert("hello")') will lead to a TypeError). Is there any tutorials that describe such a syntax?
That is an indirect eval call
Quoting from the article:
According to ES5, all of these are indirect calls and should execute
code in global scope.
So you can use these kind of "tricks" to execute eval in the global scope instead of the current one.
It works before [eval] is an array where its 0-th element is the eval function, that is, [eval][0] === eval, and you are invoking it passing the string 'alert("hello")' as the argument.
The reason your example leads to a TypeError:
window['eval'][0]('alert("hello")')
is because you left out one set of brackets that would have made it equivalent:
[window['eval']][0]('alert("hello")')
The initial syntax you gave constructs an array with one element, the function eval. The 0th element of this array is therefore the eval function, which is immediately dereferenced using the square brackets.
Unquoted eval surrounded by brackets is an Array with one element which is eval.
[eval][0]('alert("hello")')
means take the first element of the Array [eval] and pass 'alert("hello")' to it. In other words,
eval('alert("hello")')
window['eval'][0]('alert("hello")')
on the otherhand tries to get the first element of window['eval'] which is not an Array, and thus the TypeError. window['eval'] is the same as eval unless there is another variable in scope called eval.
In Javascript
[x]
is a list of one element containing x. thus
[x][0]
is just a wordy and inefficient way of saying x.
Your example
[eval][0]('alert("hello")')
is therefore just like
eval('alert("hello")')
This kind of trickery is normally found in Javascript trojan or viruses, where the author tries to disguise what is happening.
Javascript however is full of special cases and when used with eval the code can also have the meaning of forcing global evaluation instead of local evaluation.
function defun(s) { [eval][0](s); }
function defun2(s) { eval(s); }
defun2("function square(x){return x*x}")
---> undefined
square(12)
---> ReferenceError: square is not defined
defun("function square(x){return x*x}")
---> undefined
square(12)
---> 144
See Matteo Tassinari answer link for details (note that the linked article is a bit dated, so ignore details about webkit behavior).
Related
This is a very basic JS question, but this "issue" drives me crazy.
From simple algebra I would expect that both first and the second statement are vaild. But the second is always throwing "Invalid assignment" error.
Does anyone have a good explanation for it?
fieldname1 = document.getElementById("emailID1");
document.getElementById("emailID2") = fieldname2;
Thanks so much,
Most common programming languages, including JavaScript, require that the left-hand side of an assignment (the "target") be something called an l-value. That means it's an expression that denotes a place to put a value. A simple variable name, or a reference to an object followed by .propertyName suffix, works as an l-value.
In your case, the function call return value is not an l-value, because JavaScript does not make that possible (some languages do). A function call is always an r-value, meaning something that appears on the right-hand side of an assignment.
Now, in your particular case, because getElementById() returns a reference to a DOM element, you can do something like this:
document.getElementById("something").name = "frederick";
The function still returns an r-value, but that .name works as a property reference and thus as an l-value.
The assignment operator resolves the right side of the equal sign and stores it in the variable on the left side, which is what is happening in the first line.
The second line is basically trying to take the value of a variable fieldname2 and store it in a function call document.getElementById("emailID2")
JavaScript doesn't know how to resolve that at runtime, so it's throwing an invalid assignment operation.
There's more information on assignment from MDN here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators
You can't assign a value to an object itself in this case.
document.getElementById("emailID2") = fieldname2;
As i guess you want to do something like this:
document.getElementById("emailID2").name = fieldname2;
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am using CanvasJS and always used these lines here:
var chart = new CanvasJS.Chart("chartContainer",
{
...
});
chart.render();
Unfortunately, I do not know what these lines are doing. Can someone explain it to me? Thank you very much!
What are these lines doing??
Well on their own not much. In the context of a javascript engine a lot or not much.
The short version.
Creates and renders a CanvasJS.Chart, putting the chart in the DOM element identified as "chartContainer". Well it would if it was complete.
The long version.
var is a javascript token. It is used to declare a variable and is usually followed by the name or variable identifier of the variable. In this case chart. You could also use the tokens let, const, or function (and some others) which have different scope and access to the contents of the variable they declare
= is an assignment operator. It moves the data from the expression on the right to the variable/property on the left.
new (javascript token)is a special token that modifies the way a function is called (In days of old when javascript was still considered a toy it was used to make javascript look hip and cool) It is rather superfulouse in the language so you can ignore it for now.
CanvasJS (variable identifier) is a variable that was declared somewhere in the javascript code (hopefully) using one of the declaration tokens (most likely function). It has been capitalised which is significant. In Javascript when you capitalise a variable identifier you are telling the world that this is a special function that will always return an Object if called. It also tells you that it might have a special property called prototype which helps the javascript engine run your code a little quicker and helps you by simplifying your data structures using something called inheritance.
.Chart (property identifier) This is a property, the dot "." between CanvasJS and Chart signifies property of (called Dot notation, but could equally have been the not so popular, Bracket notation CanvasJS["Chart"] same as CanvasJs.Chart. )
So Chart is a property of CanvasJS. A property is like a variable but rather than being alone the property is attached to an Object. This is very handy for grouping related data and information
Because CanvasJS has a big C, Chart is most likely (but not a certainty) one of the special prototype properties of CanvasJS.
( Opening brace. When you see one of these after a variable identifier it means that the variable is a function that can be called. It at some point must have a closing brace ) What is between ( and ) are called function parameters, or arguments and are passed to the function. There is a whole set of rules governing what goes between the ( and ) and way to much to cover now.
Calling a function does a lot of special stuff, in the most basic terms the javascript engine locates that code that belongs to the function, packs its bags with arguments, goes to the function code, sets up camp, executes the function code and then returns with all the groover holiday shots. Anyways I digress
"chartContainer" first argument, a string literal. It is abstractly a devoted bit of memory that holds a "string" of characters. Strings and string literals have many uses, but looking at the content of this string I can guess what it is used for.
It is an identifier, name, or query used to find a DOM object (Document Object Model, the ugly bit hanging of the side of javascript, the dude whose party Javascript came to but nobody likes and wishes would go away) The bit of HTML that will hold the chart
, comma used to separate arguments (in this case)
{ Opening curly or Object literal. Like the string literal but instead of characters it contains properties. needs to have a closing curly at some point
... the dots by themselves in this context is just gibberish and will cause the javascript parser to stop dead in its tracks and not look at anymore code. We know it's gibberish, so does javascript, but rules are rules so we need to clean this up.
//... commented epsilon referring to the missing code.
} closing object literal.
) end of function's argument list.
; End of expression, like new it is not really needed but god (AKA Douglas Crockford) linted that it must be so, or you will be smittened by the obscure bugs and the taunts of JSLint and friend forever. (also you can not see return characters, so ; tells you this statement/expression/blockless code block, is complete.)
At this point javascript will call the function CanvasJs.Chart passing the arguments, a string and an object. The function will do its thing and with luck will return a object (we know it will be an object because the new token and that Chart has a big C). The = will give the variable identified as chart (note the small c) a referance to the returned object.
chart.render() Property of referenced object held by chart called render is a function, call it with no arguments. I am guessing that it draws a chart and that chart can be seen in the DOM inside an element that may have the id chartContainer.
I'm leaning JavaScript and I've read about the constructor property.
I tried
[].constructor
false.constructor
'abc'.constructor
And they all worked. However to my surprise when trying:
123.constructor
{}.constructor
They did not, why is that?
This is a parse issue.
When you do 123.constructor the engine experts a decimal after the 123 like 123.123
When you do {}.constructor the engine reads {} as an empty block and then reads . as the first thing in the outer block which is meaningless.
Both of which can be fixed by wrapping these with ()s
(123).constructor; // Number, note this 'boxes'
({}).constructor; // Object
I was expecting JavaScript to reject objects with duplicated properties as invalid but it accepts them in some cases.
{"a":4,"a":5} results in an SyntaxError at least in Firefox and Chrome which seems obvious due to the property a being defined twice.
However ({"a":4,"a":5}) evaluates just fine and results in an object {"a":5} in both Firefox and Chrome.
Why is the expression with the parenthesis accepted?
Summing up the responses: The first example is simply not the construction of an object but a block of labeled statements. Duplicated properities in objects are perfectly valid in which case the last definition wins.
Thanks a lot for your answers!
It is perfectly legal in ECMAScript 3 to declare duplicate properties in an object literal; the SyntaxError you get probably comes from the fact that you used an object literal as a statement, which is not possible due to the confusion with block statements ({ doSomething(); }).
If you want this to be reported as an error, you may want to switch to ECMAScript 5's strict mode: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode.
What you state has no problem if you assign it to a variable, if you don't however, you get the error you mention. Which makes all the difference from a syntax point of view.
When you wrap any structure in parens you are causing that syntax to be evaluated as an expression, the result of which is stored as a temporary variable. The error I get when not doing so in Firefox is unexpected label or invalid label, so it seems without assignment, or parens, this object construction is not treated as an object construction - instead it is treated as a block with multiple label statements that are defined illegally:
{
a: function(){
alert('a');
},
b: function(){
alert('b');
}
}
The above should be totally acceptable as an object, however you get a similar error if you evaluate it without assinging it to some form of variable, or evaluating it with parens. Put simply the duplication of the attribute name is not causing the error :)
Basically imagine your first example, but like this:
function (){
"a": 4,
"b": 5
}
That is roughly how these browsers are treating it, which is now obviously illegal javascript syntax... whereas it wasn't so obvious before.
In the first notation (parentheses-less) the javascript syntax is ambiguous. From ecmascript specification:
An ExpressionStatement cannot start with an opening curly brace
because that might make it ambiguous with a Block.
A block basically evaluates all the statements inside, equivalent to evaluating "a":4,"a":5 which is not valid JS and, in fact, returns the same SyntaxError Unexpected token :
Wrapping that code in parentheses (or, rather, a grouping operator) removes that ambiguity since an assignment expression cannot be followed by a block statement:
var test = {"a":"a","a":"b"}; //test.a === "b"
Furthermore this ambiguity can be removed by any operator or expression that cannot be used with a block statement. A practical scenario hardly comes to mind, maybe if you wanted to return an object literal as part of a conditional operator?
//this *could* come out of a JS minifier:
return x ? (foo(),{"a":"b"}) : (bar(), {"b":"a"});
Why should it not be accepted? You're simply overwriting the values. I think it's rather a feature, than an error. And it works fine for me on various browsers: http://jsbin.com/oculon/1/edit
It's like writing
var a;
a = 4;
a = 5;
alert(a);
it's not Error you just overwrite value with another
I'm guessing (though not certain) that this evaluates as an error because of the difference between the way Firefox and Chrome's JS parsers treat statements and expressions. So because it's wrapped in parentheses the second time, it's considered an expression. Since it's looking for less information in an expression, it can ignore erroneous values. You'll see that if you do...
var a = {'a': 5, 'a': 4};
console.log(a);
It works fine! And also notice that here it's in the right hand side of the statement, giving a hint that it's an expression.
var test=(a=1,[b=2]["sort"])();
This code works in Firefox resulting test=window (window object),
Is it valid JavaScript code? (I failed to find it in JavaScript references)
It's "valid" but looks completely pathological to me. From the name of the var, I'd guess someone came up with this as a feature test at some point, but failed to add a comment explaining why.
So here's what it's doing. First, the two assignments will resolve to the assigned value, so we can replace them (they do assign variables, which is a side effect, but that doesn't affect the evaluation of this expression):
var test=(1, [2]["sort"])();
["sort"] is just .sort:
var test=(1, [2].sort)();
The comma operator will return the last value in the brackets, so we can lose that 1:
var test=([2].sort)();
So now the bracketed part is creating an array with the number 2 in it, and finding the sort method of that array. It then calls that method, but because of the first set of brackets it calls it without a specified context.
In non-strict mode, a function called with no context gets window as its this.
So it tries to sort window and returns the result, which is window, as you saw.
In strict mode, which the JS consoles in Firebug and Chrome are, functions called without context get undefined as their this, which means this example throws an error, as mplungjan noted above. https://developer.mozilla.org/en/JavaScript/Strict_mode
I would expect that code to give an error.
The comma basically evaluates the expression on the left, a=1 and then the expression on the right [b=2]["sort"] and returns the result of the expression on the right.
a=1 sets a to 1, creating a as a global if it's not in the current scope.
[b=2] sets b to 2, creating b as a global if it's not in the current scope, and also creates a one-element array with the value 2.
[b=2]["sort"] returns the array .sort method (it does not call the method).
So the result of the expression in parentheses is the array .sort method which is then executed by the final (), and the result would be assigned to test except that it doesn't work because by then it is not actually called on an array.
The final assignment is the equivalent of this: var test = ([2].sort)();.