When using JavaScript's with statement, where do variables that have invalid names go?
var o = {"##$%":1,"test":2}
with(o){
console.log(test)
// Can't do this:
//console.log(##$%)
// Was it not imported, or is it just inaccessible?
}
Can you reference the code in a JavaScript engine as well?
If a property is not a valid identifier, it can't be referenced like an identifier inside with. It's not inaccessible, but your only option is to look up the property on the original object manually, like normal:
var o = {"##$%":1,"test":2}
with(o){
console.log(o['##$%']);
}
This sort of issue is not exclusive to the deprecated with statement. It occurs with the global object as well. Just like a with statement creates an object Environment Record, similarly, all code in a script is, in a sense, implicitly wrapped in a with for the global object (resulting in the global environment record).
So, for exactly the same reasons, when a property which can't be an identifier is on window, eg:
window['###'] = 'foo';
There's no way to get to foo by using a standalone identifier without explicitly referencing window first (or use some other method to get to the global object).
(of course, just like with with, properties which are valid as identifiers on window can be referenced standalone - that's why we can, for example, reference undefined and Array instead of window.undefined and window.Array. This can cause bugs...)
Where do variables […] go?
I think you have this backwards. A with statement doesn't create any variables (like a var declaration would), instead it changes the scope so that any identifier is looked up as a property on the object. Every time you access xyz, it looks if ('xyz' in o) return o.xyz else … - that's why with statements are so slow and deprecated in strict mode.
So there are no "variables that have invalid names" at all. If you used an invalid identifier in the first place, it would have thrown a syntax error and the code wouldn't even run.
Related
When I run the following simple Javascript line...console logs an error.
console.log(abc);
But when I run the above line like
console.log(this.abc); or console.log(window.abc);
the console does not throw an error. Instead it prints "undefined".
Why?
Note: 'abc' variable is not defined or declared.
It's not errornous to refer to a non-existent property, but it is erronous to refer to a standalone variable name which doesn't exist.
When one references a non-existent property on an object, undefined will be returned - that's how how things work. But standalone variable names, on the other hand, do need to be defined before referring to them, in almost all situations. Failing to define a standalone variable before trying to refer to it will throw a ReferenceError in all but 2 situations:
(1) When using typeof
console.log(typeof foo);
(2) When assigning to such a variable in non-strict mode (the variable will be implicitly created on the global object):
const arr = [1, 2, 3];
for (i = 0; i < arr.length; i++) {
// if in sloppy mode, and i hasn't been defined beforehand,
// it will be created as a global variable
}
console.log(typeof i);
If you try to assign to such a variable in strict mode when it hasn't been declared beforehand, an error will be thrown.
When you looking for a variable
console.log(abc);
Is not defined and should throw
Uncaught ReferenceError: abc
is not defined in any context at all
however
console.log(this.abc) and console.log(window.abc)
part of it is defined
console.log(this)
console.log(window)
return current objects instance and window objects respectively and have a reference point. the plain console.log(abc) has no reference point
actually it's not a variable. It is a key which is inside an object. (At this point the object is this or window). this and window created from JavaScript.
It's an interesting question to ask!.
To be able to understand this, we must understand Variable Hoisting in Jaascript.
if you want an undefined for a variable that is not declared yet , well the following would work!
console.log(abc)
var abc = 'ss';
So, here if we try to access a declared variable before it is initialized then undefined is actually assigned at the top of function execution. in other words, all the variables are hoisted to the top of their immediate scope level and are assigned undefined until they reach the initialization point.
to give you a blunt answer, trying to use an undeclared variable would give you Reference Error while trying to access a declared variable before the initialization would give youundefined
and, for objects like this and window well they are available objects . so basically at this point people say, In Javascript everything is present, meaning, trying to access a property that is not yet there in a js object would give you undefined.
On most browsers and Javascript environments that respect Javascript specification (this may change in other javascript environments where there is no console):
Any property that has not been assigned a value or non existent property (or a function without a return statement) returns undefined.
In the first examples, the dot operator is being called. The behaviour in case you access a non existent property is defined and it is that to return undefined, which is a valid js type. Therefore undefined is being logged.
On the last example, on the other hand, the non existent variable throws a ReferenceError. This happens directly, as unlike the first case, no context has been accessed, no dot operator is being called and this is just a plain error.
It is the normal JavaScript behavior.
Lets consider a variable name
var name;
console.log(name);
The above wont throw an error, because the variable name was declared before using it in console.log.
console.log(name);
This will throw a reference error because you did not declare the variable first.
But,
If name is accessed from an already defined variable( e.g. window, this ), it wont throw an error whether defined or not. Just like the below will simply print undefined, reference error wont be thrown.
console.log(window.name);
Note that window is already defined by the browser.
Notwithstanding,
console.log(window_a.name);
the above will throw a reference error because name is being accessed on an undefined variable window_a.
var window_a = {};
console.log(window_a.name);
This wont throw reference error because window_a is now declared.
function log(this) {
console.log(this);
}
It throws the error Unexpected token this. So why doesn't JavaScript accept this as an argument?
this is a reserved keyword so it can't be used as a variable name.
If you want to override the this value for a function, you can use call or apply.
function log() {
console.log(this);
}
log.apply({ custom: "this value" });
this has special meaning in the language. It's an identifier, but can only be defined automatically in specific situations, never explicitly by the developer.
Other identifiers that are automatically defined can still be defined by the developer, like arguments, undefined and window, though it should be avoided in most cases.
To add clarity, in programming an identifier is a label used by a programmer to reference a value.
In JS, this is indeed a keyword, which, according to ECMAScript semantics, prevents it from being explicitly declared as an identifier. This does not mean that it isn't an identifier at all, which it clearly is since it will always let the programmer reference a value.
So something being a keyword does not mean that it isn't an identifier. It does mean though that in JS, you don't have the option of explicitly declaring an identifier with that name, though other languages do sometimes allow this.
Mozilla says that variables are properties of the global object. If an object has a property that isn't defined, then trying to access it does not create a reference exception - it simply returns that the property is not defined.
If there is such a global object - then why does accessing its properties (ie: variables) that do not exist create reference errors? What is precisely the difference between these two scenarios?
Example:
console.log(x) //x is not declared -> reference error
var x = new Object();
console.log(x.property); //console.log: undefined
tl;dr: The way the variable is accessed makes all the difference, not how it is stored.
First some background:
There are basically two ways how variables are "stored".
In a declarative environment, variables are stored in an internal data structure that is not accessible from user code.
In an object environment, variables are stored as properties of a user code accessible object. The global environment happens to be an object environment (it's a bit more complicated than that but lets keep it simple). Therefore global variables are properties of the global object.
So why does accessing a non-existing global variable throw an error? Because it is not relevant how the variables are stored, only how the are accessed.
foo and window.foo are simply two different ways of accessing a global variable.
The language rules for evaluating a variable (foo) explicitly say that if the variable doesn't exist, throw a reference error (again, no matter how it is stored).*
The language rules for evaluating property access (window.foo) say that if the property doesn't exist, undefined should be returned.
And if you think about, this makes much more sense from a consistency perspective. Accessing foo should have the same result, no matter whether the variable is stored in a declarative environment or an object environment.
*: To be more precise: It's the GetValue function that causes the error to be thrown. GetValue is called almost everywhere when resolving a variable (exceptions are typeof and the grouping operator (...)).
For example, I see that undefined is described like a predefined global variable, while null is described like a keyword.
What's the difference?
null is not a keyword; it's a special literal value, like true. See the spec.
undefined is not a keyword either. First, it's the name of a global property with some special behaviors: it is non-configurable and non-writable (in modern browsers), meaning you cannot change its value. See the spec.
Second, it's a special value which is the value of the undefined property, the value of uninitialized variables, the return value of functions without explicit return statements, and what the void operator evaluates to.
Third, it's a type, whose only value is the undefined value.
In JavaScript, some identifiers are reserved words and cannot be used as variables or function names those called keywords e.g break, case, catch, continue, debugger, default, delete, do, else, false, finally, for, function these are some reserved keywords in javaScript.
Whereas A variable declared outside a function, becomes GLOBAL. A global variable has global scope: All scripts and functions on a web page can access it.
Have you ever taken a look under the hood at the jQuery 1.4 source code and noticed how it's encapsulated in the following way:
(function( window, undefined ) {
//All the JQuery code here
...
})(window);
I've read an article on JavaScript Namespacing and another one called "An Important Pair of Parens," so I know some about what's going on here.
But I've never seen this particular syntax before. What is that undefined doing there? And why does window need to be passed and then appear at the end again?
The undefined is a normal variable and can be changed simply with undefined = "new value";. So jQuery creates a local "undefined" variable that is REALLY undefined.
The window variable is made local for performance reasons. Because when JavaScript looks up a variable, it first goes through the local variables until it finds the variable name. When it's not found, JavaScript goes through the next scope etc. until it filters through the global variables. So if the window variable is made local, JavaScript can look it up quicker.
Further information: Speed Up Your JavaScript - Nicholas C. Zakas
Undefined
By declaring undefined as an argument but never passing a value to it ensures that it is always undefined, as it is simply a variable in the global scope that can be overwritten. This makes a === undefined a safe alternative to typeof a == 'undefined', which saves a few characters. It also makes the code more minifier-friendly, as undefined can be shortened to u for example, saving a few more characters.
Window
Passing window as an argument keeps a copy in the local scope, which affects performance: http://jsperf.com/short-scope. All accesses to window will now have to travel one level less up the scope chain. As with undefined, a local copy again allows for more aggressive minification.
Sidenote:
Though this may not have been the intention of the jQuery developers, passing in window allows the library to be more easily integrated in server-side Javascript environments, for example node.js - where there is no global window object. In such a situation, only one line needs to be changed to replace the window object with another one. In the case of jQuery, a mock window object can be created and passed in for the purpose of HTML scraping (a library such as jsdom can do this).
Others have explained undefined. undefined is like a global variable that can be redefined to any value. This technique is to prevent all undefined checks from breaking if someone wrote say, undefined = 10 somewhere. An argument that is never passed is guaranteed to be real undefined irrespective of the value of the variable undefined.
The reason to pass window can be illustrated with the following example.
(function() {
console.log(window);
...
...
...
var window = 10;
})();
What does the console log? The value of window object right? Wrong! 10? Wrong! It logs undefined. Javascript interpreter (or JIT compiler) rewrites it this way -
(function() {
var window; //and every other var in this function
console.log(window);
...
...
...
window = 10;
})();
However, if you get the window variable as an argument, there is no var and hence no surprises.
I don't know if jQuery is doing it, but if you are redefining window local variable anywhere in your function for whatever reason, it is a good idea to borrow it from global scope.
window is passed in like that just in case someone decides to redefine the window object in IE, I assume the same for undefined, in case it's re-assigned in some way later.
The top window in that script is just naming the argument "window", an argument that's more local that the global window reference and it what the code inside this closure will use. The window at the end is actually specifying what to pass for the first argument, in this case the current meaning of window...the hope is you haven't screwed up window before that happens.
This may be easier to think of by showing the most typical case used in jQuery, plugin .noConflict() handling, so for the majority of code you can still use $, even if it means something other than jQuery outside this scope:
(function($) {
//inside here, $ == jQuery, it was passed as the first argument
})(jQuery);
Tested with 1000000 iterations. This kind of localization had no effect in performance. Not even a single millisecond in 1000000 iterations. This is simply useless.