There are two possible cases where such typo could be an issue:
Names of variables
Such as in:
var inIframe = ...
...
console.log(isIFrame); // Throws `ReferenceError: isIFrame is not defined`
The fact that you discover the mistake at run time can eventually be disturbing. The case is straightforward if the declaration of a variable and the use of it wrongly typed are close to each other, but could be much more problematic if the typo is buried inside conditional statements, loops and functions.
The fact is that in JavaScript, it's perfectly legal to use variables without declaring them first:
a = 5; // See, no `var` here.
console.log(a);
But the fact that the current JavaScript interpreter doesn't check that a variable was declared before being used really doesn't matter that much: such typos are very easy to avoid by using linters.
JavaScript has a great linter tool jslint written by Douglas Crockford. The following code:
/*jslint browser: true, devel: true*/
var a = function () {
'use strict';
var b = 123;
console.log(b);
};
produces no errors, but if you change:
console.log(b);
to:
console.log(c);
you'll see the following errors:
Unused 'b'.
Undeclared 'c'.
making it obvious to figure out the typo.
In your case, jslint will immediately figure out that isIFrame is unused and point you out to it. Obviously, it won't be able to understand that you wanted to write inIframe, but at least, you won't waste twenty minutes debugging your code.
See also:
An answer, which, among others, compares jsLint and jsHint and explains why jsHint should be avoided.
My article explaining why is it crucial to use linters and static checkers.
Names of properties
Such as in:
var something = {
"inIframe": true
};
...
console.log(something.isIFrame); // Shows `undefined`
The dynamic nature of JavaScript prevents both the interpreter and the linter from determining that something.isIFrame doesn't point to anything. In fact, there could be an isIFrame inside, coming from multiple sources, like prototypes or direct assignment. Also, something can be initialized like this:
var something = JSON.parse('{"inIframe": true}');
where the actual string could be a result of a REST call, meaning that the interpreter (or the linter) couldn't possibly know what's inside. Google Closure Compiler may help here, but at a cost of requiring you to manually describe the structure of something, similarly to what one would do in a static strongly-typed programming language.
The next thing is to determine why is JavaScript actually returning undefined instead of throwing ReferenceError (or a similar exception) at run time when encountering an access to a property which doesn't exist.
Technically, until the apparition of proxy in ECMAScript6, nothing prevents to actually throw an exception, since, I imagine, the JavaScript engine knows that a given property doesn't exist. It should also be a possibility for the engine to make a difference between getting the property and setting it (like it's already done for variables; a = 123; is legal, but console.log(b); throws an exception).
On the other hand, the choice of actually returning undefined makes sense too, for two reasons:
If you expect isIFrame to be either false or true, receiving undefined gives you a good hint that there is something wrong with the name of the property. The same applies to most cases where you expect a value, would it be a number, a string, or an object representing some business entity.
The case which worries me much more is when, expecting a boolean, you write:
if (something.isIFrame) {
// This will never execute, since `isIFrame` doesn't exist.
} else {
// This will execute every time.
}
Here, JavaScript doesn't help you much, since it silently swallows the undefined and simply executes the elseblock every time. This being said, it shouldn't take much time to figure out that there is something wrong around theif/else. The next step is to run a debugger and check for the actual values: as soon as you see theundefined` instead of a boolean, you have a hint.
You may on the other hand expect the situation where the value may simply not be here.
For instance, I'm currently working on a node.js application which receives messages about servers. Sometimes, a message is sent not by the server itself (a virtual machine), but by the host: in this case, the message contains a replacementIP property with the IP address of the concerned virtual machine.
If I want to display the IP address, all I have to do is:
var ipToDisplay = message.replacementIP || context.senderIP;
If JavaScript was throwing exceptions when accessing non-existent property, this would force me to write this instead:
var getActualIP = function (message, context) {
try {
return message.replacementIP;
} catch {
return context.senderIP;
}
};
[...]
var ipToDisplay = getActualIP(message, context);
I find it much more difficult to follow.
So you have two cases here: in the first one, the choice of the designers of JavaScript appears problematic in a specific case, and causes you to launch your debugger. Not that nice, indeed. On the other hand, the second case shows that the designers' choice makes it possible to write very compact code in a lot of situations; I find it very nice.
So what about an opt-in "using strict undefined"?
Not sure it's a good idea, for the simple reason that adding features to a language should be taken very, very seriously.
Any additional feature takes literally months, and given the nature of JavaScript, would need to be implemented in every browser. As usual, the one with the name starting by “I” will be late, and so you'll find yourself including "using strict undefined" in your code, while knowing that this browser will plainly ignore it: not fun when it comes to debugging.
Compare this to, for instance, ECMAScript 6th String Interpolation feature. String interpolation brings a huge benefit in terms of code readability and maintainability: most developers who used Python or Java are familiar with this feature, and they will happily use it in JavaScript. It will break existent code, but given its importance, it's worth the risk, and worth the time spent implementing it.
Default parameter values? Same thing: great benefit for everyone, and no risk of breaking existent code.
But "using strict undefined"? I'm not convinced that the edge case illustrated below is not that important, especially since it's easy to find what's happening with the help of a debugger. If you write software for which it is not acceptable to access non-existent properties, Google Closure Compiler is an option. Switching to a different language is another option.
s["in"+"Iframe"] = true;The linter will have no way to know at linting time whether or nots.inIframeis valid ors.isIframeis valid. In fact your own example shows the issuevar obj = JSON.parse("{\"c\":123}");As for breaking stuff "use strict" already breaks stuff. That's why it's opt in. I was also suggesting an opt in feature. So it wouldn't break anything because you'd be opting in. – gman Nov 11 '15 at 12:18s["in"+"Iframe"]example is irrelevant, since you're simply screwing up with linter/stricter interpreter. It's exactly the same thing that using Reflection in languages such as Java or C# and blaming the compiler that it couldn't tell you thattypeof(Product).GetMethod("FindPrice").Invoke(...)will throw an exception becauseProductdoesn't containFindPricemethod. – Arseni Mourzenko Nov 11 '15 at 14:15svariable containsfooBar. If you don't like this fact, dynamic languages are not a good choice for you: in a language such as C++ or Java,s.fooBarwill result in a compiler error. – Arseni Mourzenko Nov 11 '15 at 16:45AttributeError: 'SomeClass' object has no attribute 'fooBar'. Here's another example. At runtime it throwsKeyError: 'fooBar'JavaScript could possibly benefit by optionally following the same strictness – gman Nov 11 '15 at 18:19AttributeErroris an exception which happens during run time. This has nothing to do with an error which will be generated, for instance, by a C# compiler when it builds the IL representation of your code. If you expect JavaScript from throwingReferenceError, well, that's a choice language designers haven't made. It would be a valid choice, but the choice they made to returnundefinedlooks valid too. – Arseni Mourzenko Nov 11 '15 at 18:24undefinedis valid too. One of the benefits might be is that it's easier to write a conditional rather than a try/catch. Also, it makes it very easy to dismiss a missing element when this is what you want; for instance:product.price || 0. – Arseni Mourzenko Nov 11 '15 at 20:06