It seems a solution for error message
TypeError: Cannot read property XXX of undefined
when using something like
if (item.property) {....}
is no longer valid. In fact, it seems even getting that error message is no longer possible because now you get
ReferenceError: item is not defined
I came across this because quite some time ago I had posted an accepted and 13 times upvoted answer to just such a question. I was not the only one giving the code that I gave as an answer, here is another one - same code, for the same type of problem. But those solutions now result in an error immediately!
I DID test my code, and if it had not worked it would hardly have been upvoted and accepted, same for the other Q/A I link to.
What is going on? I can't seem to provoke that error message (Cannot read property XXX of undefined) any more either, I tried by accessing a property of an undefined or a null variable. Have I gone mad, or has something else changed?
No, this hasn't changed (there's something similar that's changed, but not this; more below). Here's the difference: If item isn't declared, then you'll get the error about item. If item is declared but has the value undefined, you'll get the error about reading a property of undefined. This has always been the case.
You mentioned Firefox. Firefox's error messages for these two different conditions are confusingly similar. If the variable is undeclared, it says:
ReferenceError: item is not defined
But if the variable is declared and has the value undefined, it says:
TypeError: item is undefined
Note the difference, but the extreme similarity. I would say Firefox's error messages are poor in this regard. Chrome's are more clearly distinct:
ReferenceError: item is not defined
TypeError: Cannot read property 'property' of undefined
But that's just the error message. The underyling issue, trying to read the value of an undeclared symbol, has always been an error.
Re the two answers you linked to: I'm sorry, but they were always wrong for the undeclared case (and right for the undefined case), this is just something that people don't understand well. If item may be completely undeclared, you can't use that idiom. You can use typeof, though:
if (typeof item !== "undefined" && item.property)
typeof is fine with undeclared symbols, but reading the value of an undeclared symbol is an error, as has been for as long as we've had JavaScript.
Here's a question from 2011 about this. The accepted answer with a score of 1,016 talks about typeof.
Here are examples of both cases:
Undeclared:
// Note that `item` isn't declared anywhere at all
try {
if (item.property) {
snippet.log("true");
}
}
catch (e) {
snippet.log((e.name || "Exception") + ": " + (e.message || String(e)));
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Declared but has the value undefined:
var item;
try {
if (item.property) {
snippet.log("true");
}
}
catch (e) {
snippet.log((e.name || "Exception") + ": " + (e.message || String(e)));
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The similar thing that's changed is how assigning to something that isn't declared at all is handled:
item = "foo";
In loose mode, that's an implicit global variable, even if the assignment is inside a function. In ES5's strict mode, though, it's an error.
But that doesn't relate to reading the value of an undeclared variable, which was always an error, just writing to it.
From the OP:
when using something like
if (item.property) {....}
is no longer valid. In fact, it seems even getting that error message is no longer possible because now you get
That is incorrect.
In both linked questions, the OPs mention item being undefined, which means they are declared, which means the answers, if (item && item.property), will work exactly as expected.
Nothing has changed in this regard, so to answer your question:
why things that worked don't work any more. I link to TWO answers that were accepted and highly upvoted that don't work (any more)!
Those answers work just fine. Unless you change the parameters of the question, which is what you're doing.
(You're assuming item is undeclared instead of undefined)
There's a difference between a typeof being "undefined" and the actual variable being undefined:
Related
I have encountered this issue several times already. Sometimes it even does nothing, while sometimes it reports this error, seemingly under the same conditions.
I want to check IF something isn't undefined and in such case I want to perform an action. But when it indeed is undefined, I am SOMETIMES getting an error report that it can't be read, because the property is undefined. I would like to understand the principle of this error that seems to appear under certain conditions. Thank you.
The code is for example as follows (part of a loop):
if (objectName[varName].enemy !== undefined)
{
console.log("enemy found")
}
Your objectName or varName could be undefined, add checks for those too
Recently I investigated a situation in which a programmer inadvertently passed undefined into addEventListener, thus:
window.addEventListener('load', undefined);
No error was thrown. It's as if JavaScript is willing to invoke undefined. But what in the world is undefined()? I have tried all sorts of things, e.g.:
console.log(undefined() === null);
console.log(typeof undefined());
but I never get anything back.
Edit added for clarity: My original question was based on a mistake, as I had not set my Developer tools to log errors to the console. The above two commands (but not the call to addEventListener) DO throw errors in a browser, as answers and comments below indicate.
It's as if JavaScript is willing to invoke undefined.
No, addEventListener is specified to ignore null, which JavaScript’s undefined is converted to. undefined is never called.
Further proof that JavaScript is not willing to invoke undefined, in a browser:
> undefined()
Uncaught TypeError: undefined is not a function
at <anonymous>:1:1
You can do something like this to find the type of passed arguments:
var myVar;
Object.prototype.toString.call(myVar);
and it will return "[object Undefined]"
same for other use cases like if myVar is a string as below:
var myVar = 'It is a string';
Object.prototype.toString.call(myVar);
it will retrun "[object String]"
It will return:
Undefined is not a function
console.log(typeof undefined());
If you run it console on a browser it will return undefined not a function. Undefined does not have any value unlike null which is an object.
null means that something exists, but has been told it has no value.
undefined means that thing has not been given a value, usually because it hasn't been declared/initialized.
In Javascript, undefined is a primitive. It's falsey, so it evaluates to False if used in conditional.
Javascript is not a strongly typed language, so there's nothing to check that a callback function is a function until it's called. In fact Javascript doesn't care how many arguments are passed or what their type is, everything's just dumped in when a function is invoked, and it's up to the function how to handle the arguments.
For example in many enumerable methods, they pass back to you (index, value, array). It doesn't matter if your function looks for these values or assigns them a temporary variable, they're still passed. Both a.forEach(function(index){}) and a.forEach(function(){}) actually have access to all 3 of the variables mentioned.
In Chrome, try the following in the console. First
console = 0;
to assign the value 0 to console. Then
console // (prints `0`)
to check we have correctly overwritten console. Finally,
delete console
Surprisingly, console now holds the original Console object. In effect, the delete keyword "resurected" console, instead of exterminating it!
Is this expected behaviour? Where is this implemented in the Chromium code?
As mentioned in MDN's documentation on delete:
If the delete operator succeeds, it removes the property from the
object entirely, although this might reveal a similarly named property
on a prototype of the object.
Your delete simply unshadows native property inherited through prototype chain.
Some browsers have window inherit from native prototype and you'll have check out sources to see how property is inherited, if you really want to know that much details, but mostly they work just like JS' own.
Got it:
I've managed to prove the console is a property of the global object: just open your console and type: this.parent or window.parent. This will show a more complete list of properties and methods at your disposal. Including console: Console, about 2/3 of the way down, just below chrome: Object (interesting...:)). I thought of this when I remembered that I somehow managed to change the CSS rules of the console itself (in chrome, don't ask me how I got there, I can't remember). Bottom line: console ís a property of the window object. I think this backs up my explanation rather well.
#Randomblue: Since you're interested in how this is implemented in v8 you can check the trunk here, or browse the bleeding. Somewhere you'll find a test dir, that has a number of files that deal with delete. Special attention is given to delete used on global variables/properties: they can't be deleted, in other words: the console is never really gone. I would like to know why this answer went from being voted helpful and accepted to not-helpful and not-accepted, though...
It's perfectly simple. Console isn't some random, stand-alone, object. It's actually a property of the global object. Open your console and type this.console === console or window.console === console. It logs true, of course.
So thanks to implied globals console = 0 is pretty much the same as window.console = 0. You're sort of reassigning a property of an instance. The difference with normal objects is that the global object isn't just any old object: it's properties cannot be deleted (somewhere here on MDN). So your global is masking the console object, which is still there, you've just lost your reference too it:
var bar = window.console;
console = 12;
bar.log(console);//logs 12, bar is now an alternative reference to the console object
delete console;//unmasks the console reference
console === bar;//true
Don't, for a moment, be fooled into thinking the global object doesn't have a prototype. Just type this.constructor.name and lo and behold: Window with a capital W does appear. Another way of double checking is: Object.getPrototypeOf(this); or Object.getPrototypeOf(window);. In other words, there are prototypes to consider. Like always, the chain ends with Object.prototype:
Object.getPrototypeOf(Object.getPrototypeOf(window));
In short, there is nothing weird going on here, but the weird nature of the global object itself. It behaves as if there is some form of prototypal inheritance going on. Look at the global object as though it were set up like this:
this.prototype.window = this;//<-- window is a circular reference, global obj has no name
this.prototype.console = new Console();//this is the global object
this.hasOwnProperty(console);//false
console = 0;//implied global
When attempting to access console, JS finds the property console you've just set prior to the instance of the Console object, and happily returns its value. The same happens when we delete it, the first occurance of console is deleted, but the property higher up the prototype chain remains unchanged. The next time console is requested, JS will scan the inheritance chain and return the console instance of old. The console-object was never really gone, it was merely hidden behind a property you set yourself.
Off topic, but for completeness' sake:
There are a few more things too it than this (scope scanning prior to object/prototype chain searching), due to the special character of the global object, but this is, AFAIK, the essence of it.What you need to know is that there is no such thing (in JS) as an object without (at least) 1 prototype. That includes the global object. What you're doing merely augments the current global object's instance, delete a property and the prototype takes over again. Simple as that. That's what #Peeter hinted at with his answer: implied globals are not allowed in strict mode, because they modify the global object. Which, as I tried to explain here, is exactly what happens here.
Some properties of the window object aren't deletable. True is returned because you aren't running in strict mode. Try the following (not in console):
"use strict";
delete console;
and you will get an exception (JSFiddle).
You can read more about how this is handled at http://es5.github.com/#x11.4.1
First, this is not just the console, you can do this with every native property every browser-defined property on window.
setTimeout = 0;
setTimeout //=> 0
delete window.setTimeout;
setTimeout //=> function setTimeout() { [native code] }
Properties that are part of the ECMA-Script Spec can be fully overwritten & deleted:
Array = 0;
Array //=> 0
delete window.Array;
Array //=> ReferenceError
You can nearly overwrite any property on window, delete the overwrite and get back to the normal function.
The simple reason for this is that console and all the other native global functions browser defined properties are not linked to the DOMWindow Object via javascript but via C++. You can see the console being attached to the DOMWindow right here and the implementation of DOMWindow here
That also means that the window object is somehow a C++ Object masked as a javascript object the window object is at least partly defined by C++, and it is not prototypical inheritance doing the magic: Take for example:
window.hasOwnProperty('console') //=> true, console is defined directly on the window
window.__proto__.hasOwnProperty('console') // => false, the window prototype does not have a console property
Also, if it was prototypical inheritance, the following would lead to console returning 3:
window.__proto__.console = 3;
delete console;
console //=> still returns console;
window.hasOwnProperty('console') //=> the window still has it.
The same with a property respecting prototypical inheritance:
window.someProp = 4;
window.__proto__.someProp = 6;
someProp //=> 4
delete someProp;
someProp //=> 6
Therefore, when you set console to anything, it is gone and can only be resurrected by (hoorray for the irony): delete console.
So, what it means is that you cannot delete any native properties on the window object. Try to delete window.console when it is not overwritten, it will just pop up again. The fact that you are able to overwrite it in the first place (even in strict mode) without receiving any kind of warning (in my eyes) one of the key vulnerabilities of javascript (set setTimeout on nearly any page to 0 and see it tear itself apart), but as they say in spiderman:
With great power comes great responsibility
Update
To include a hint that this is specific to the implementation of the browser / engine and not any requirement of the language itself: In nodejs, deleting both engine-specified properties and ecma-script properties on the global object works:
delete this.console //=> true
console //=> ReferenceError
delete parseInt //=> true
parseInt //=> ReferenceError
The exact same thing happens in Firefox.
I'm assuming the following, based on observations of my own.
Variables are first checked to see if they match local variables, if not, then it will be checked to see if they match window.variable.
When you set console to 1, you set the local variable console to 1, so any lookups will see that instead of window.console (which still exists). When you delete console the local variable console gets deleted. Now any lookups of console will match window.console. That's why you get the behaviour you get.
I am assuming this based on experimenting with the JavaScript interpreter in Firefox.
And, I'm sorry about incorrect terminology (feel free to edit), I'm not that experienced with namespaces.
The delete operator removes a property from an object.
...
You can use the delete operator to delete variables declared
implicitly but not those declared with the var or the function
statement.
See delete on MDN
Edit:
See also Understanding delete if you're really into hardcore JavaScript.
What happens is you are overwriting the objects prototype, then you delete the overwritten value and what is left... is the original object, which is it's prototype.
Expected behavior. Little known fact that the Javascript console does not run in the browser's global space, but rather it runs within its own anonymous function.
I know that different browsers handle things differently, but in short -- delete does not operate as expected because it isn't operating in the global space.
If you really want to see things break, try playing with delete window.console
Ok, it is official -- I'm an idiot. One of the new features in ECMAScript is the ability to declare a property as dontdelete. Sorry about that confusion.
I have a window, where before being closed I refresh the underlying page.
if(opener && typeof(opener.Refresh) != 'undefined')
{
opener.Refresh();
}
If I moved away from the original opening page, this code would throw a "Permission Denied" error.
Debugging the code revealed that typeof(opener.Refresh) was equal to "unknown" instead of the expected "undefined".
As far as I'm aware "unknown" is not one of the return values for typeof, so how and why would this value be returned?
Further Information
I avoided the error by changing the check to:
if(opener && typeof(opener.Refresh) == 'function')
However examples like this (detecting-an-undefined-object-property-in-javascript) do not seem to factor "unknown" into the equation.
According to a duplicate question at Bytes, the typeof value unknown is added to JScript version 8, along with date.
A comment to a blog by Robert Nyman can also be explanatory:
Internet Explorer displays “unknown” when the object in question is on
the other side of a COM+ bridge. You may not know this or realize
this, but MS’s XMLHTTP object is part of a different COM+ object that
implements IUnknown; when you call methods on it, you’re doing so over
a COM bridge and not calling native JavaScript.
Basically that’s MS’s answer if you try to test or access something
that’s not a true part of the JScript engine.
Try in operator. I had the same problem (with applet) and I solved it using in:
if("Refresh" in opener) {
opener.Refresh();
}
The ECMAScript specification states that for host objects the return value of the typeof operator is:
Implementation-defined except may not be "undefined", "boolean",
"number", or "string".
I believe the unknown value is only ever returned in Internet Explorer. Interestingly, MSDN does not mention it:
There are six possible values that typeof returns: "number," "string,"
"boolean," "object," "function," and "undefined."
So I have been working with javascript for a website I am designing, shocker I know, I was trying to find a way to test if a variable did not exist or wasn't defined. After getting through this I think being undefined and not existing are two different things. Also I think its highly unlikely I found a bug but maybe someone with a better understanding of Javascript can explain to me why the following code works the way it does.
<script type="text/javascript">
var t1="";
var t2;
if (t1==undefined) {document.write("t1 is undefined");}
if (t2==undefined) {document.write("t2 is undefined");}
</script>
The above code returns "t2 is undefined".
<script type="text/javascript">
var t1="";
if (t1==undefined) {document.write("t1 is undefined");}
if (t2==undefined) {document.write("t2 is undefined");}
</script>
This second code crashes I believe. So in the first code t2 exists but is not defined? and in the second code it needs to exist before it can be undefined? I just figured that if I did not write "var t2;" then tested for it, it would be undefined. Hopefully I have explained this question enough.
It's not a bug. In fact, the typeof operator is the only place where you can use an undeclared variable without getting an error.
See my answer Internet Explorer: "console is not defined" Error for a detailed explanation
edit:
This is how it's defined in the specs:
The production UnaryExpression : typeof UnaryExpression is evaluated as follows:
1. Let val be the result of evaluating UnaryExpression.
2. If Type(val) is Reference, then
a. If IsUnresolvableReference(val) is true, return "undefined".
...
Everywhere else, IsUnresolvableReference==true results in an error.
Well in your case if you have:
var t1 = "";
You will declare an empty string so it is normal to be "defined";
Whilst by doing:
var t2;
You are not defining it as any type of javascript object
It seems that there's a confusing naming convention here;
We can say in the first case, you define variable t2 itself but it does not have a value defined. You can think the "undefined" property as the "value-undefined" to be more precise.
In the second case, you have t2 variable itself is NOT defined, thus you will get an error when you try to use it in code: "variable undefined", this error is because of a different reason but it is named similarly, making the situation a little confusing. Think this error as "variable-undefined" to be more precise.
I think you can just use the property "null" instead of the "undefined" in the first case to be clear.
var t1="";
var t2;
if (t1==null) {document.write("t1 is null");}
if (t2==null) {document.write("t2 is null");}
and;
var t1="";
if (t1==null) {document.write("t1 is null");}
if (t2==null) {document.write("t2 is null");} // this line gives error because t2 variable is undefined