hasOwnProperty and ECMAScript 5 strict mode - javascript

I'm curious: anyone knows why the ECMAScript5 specification hasn't tightened more the predefined object prototype's properties in strict mode? For instance, it seems like there's no info regarding the way hasOwnProperty is defined. I've tried redefining it (and tested the code in FF4 beta) and I was able to get away with this. If I didn't do anything wrong, then this means that anyone can still redefine the Object.prototype.hasOwnProperty property and really screw all the code that relies on it for working property...
thoughts on this?
EDIT: a little more info as I dig through the spec...
As I've put in a comment below, you can't really change Object.prototype in strict mode due to the metadata that was applied to it (Writable, Enumerable and Configurable are all set to false) and FF 4 beta (which I'm using to run my tests) does generate the exception.
thanks.

And? I can kill of everything on Object.prototype if I wanted to, don't include such code in your project/site, no do something better, find those idiots who are doing such things and make sure to kick'em in the balls.
I mean, I can even screw up any given Python (2.x) program by doing True = False.
You can never protect against idiots. Never. Try to educate or avoid them.
EDIT
To clarify the impossibility of this, if you encapsulate your script into an anonymous wrapper (as you should do if you use it with other code) the "use strict" will be local to your code.
That means, if the evil idiot code does not use strict mode on its own - and they won't... unless they are total idiots, which I'm not talking about here - they run in ES3 and your beautiful strictness doesn't even exist.

Related

Simple Js program comes up NaN and objectHtmlSpanElement [duplicate]

This question already has answers here:
Do DOM tree elements with IDs become global properties?
(5 answers)
Closed 5 years ago.
Just today after a couple of years of javascript programming I came across something that left me startled. Browsers create objects for every element with an id. The name of the object will match the id.
So if you have:
<div id ="box"></div>
You can do:
alert(box); //[object HTMLDivElement]
Without first assigning anything to that variable. See the demo.
This for some reason seems to be in the standards even though it can break the code in some cases. There is an open bug to end this behavior but I'm more interested in getting rid of it now.
Do you guys know if there is a way to disable this (strict mode maybe)? Am I giving this too much importance? Because it certainly seems like a bad idea. (It was introduced by IE to give you a hint).
Update: It seems FF only does this in quirks mode. Other browsers like IE6+ and Chrome do it right off the bat.
ECMAScript 5 strict should help with this as you cannot use undeclared variables. I'm not sure which browsers currently support strict mode but I know Firefox 4 does.
The HTML spec you linked mentions a proposal to reduce pollution of the global scope by limiting this behavior to quirks-only.
I don't know if this feature is in the original spec but I do expect it to be removed, prohibited or otherwise nullified in subsequent versions of ECMAScript. ES6 will be based on ES5 strict.
JavaScript has many features that make it easier to use for beginners and novices, I suspect this is one such feature. If you're a professional and you want quality code use "use strict"; and always JSLint your code. If you use these guidelines this feature should never bother you.
Here is a useful video about ES5 courtesy of YUI Theater (it's already 2 years old though, but still relevant currently as there is no ES6 yet).
I don't think this is much of a big deal. It seems messy especially to those of us who think about global namespace pollution and conflicts, but in practice it doesn't really cause a problem.
If you declare your own global variable, it will just override anything the browser created for you so there's not really any conflict. The only place I could see it potentially causing a problem is if you were testing for the existence of a global declaration and an "auto" global based on an object ID got in the way of that and confused you.
In practice, I've never seen this to be a problem. But, I'd agree it seems like something they should get rid of or allow you to turn off.
Yes most browsers do this but then again like you said some don't (firefox) so don't count on it. It's also easy to overwrite these variables in js, I can imagine something like container might be overwritten right of the bat by someone using that variable without declaring it first.
There is no way to turn this of in chrome afaik but even then it might be a hassle to figure this out and fix it for all browsers.
Don't give it too much importance, but beware of it. This is one of those reasons why you would evade the global scope for variables.
For the sake of completion, these browsers definitly do it by default: Chrome, IE9 & compat, Opera
Update: Future versions of ECMAScript might include an option of some sort since yes discussion is going on, but that will not fix the 'problem' in older browsers.
I don't think there's a way to disable it, but you don't need to put much importance to it. If you are afraid of unpredictable bugs, you could avoid them by using JSHint or JSLint. They will help you avoid mistakes. For example, they will warn you if you use an undeclared variable.
The problem here is that the global scope has objects defined in it at runtime by the browser, and you would like to prevent these definitions from interfering with your code. I'm not aware of a way to turn off this behaviour, but I do have two workarounds for you:
1) As suggested in the article you linked to, you can work around this by ensuring that you define each variable before you use it. I would achieve this by running my code through JSLint, which warns about this sort of thing (in addition to a bunch of other common errors).
2) However, since it's possible to forget to run your code through JSLint, you might prefer a step in the tool chain that you can't forget. In that case, have a look at CoffeeScript - it's a langauge very similar to javascript that you compile into javascript before use, and it will insert the correct var definitions for you. In fact, I suspect that you can't write code that relies on the automatic element variable creation using CoffeeScript.
This is what I've been able to come up with to remove global variables that are automatically created for DOM objects with an ID value:
function clearElementGlobals() {
function clearItem(iden, item) {
if (iden && window[iden] && (window[iden] === item)) {
window[iden] = undefined;
}
}
var list = document.getElementsByTagName("*");
for (var i = 0, len = list.length; i < len; i++) {
var item = list[i];
clearItem(item.id, item);
clearItem(item.name, item);
}
}
This gets a list of all objects in the page. It loops through looking for ones with an id value and when there's an id value and a global variable exists for it and that global variable points to that DOM object, that global variable is set to undefined. As it turns out browsers also do this same auto-global for some types of tags with a name attribute (like form elements) so we clear those too.
Of course, this code can't know whether your own code makes a global variable with the same name as the id so it would obviously be best to either not do that in your own code or call this function before your global variables are initialized.
Unfortunately, you cannot delete global variables in javascript so setting it to undefined is about the best that can be done.
FYI, I tried doing this the other way around where you enumerate global variables looking for variables that are an instance of HTMLElement and that have a name that matches the id of the element they point to, but I couldn't find a reliable way to enumerate global variables. In Chrome, you can't enumerate them on the window object even though you can access them through the window object. So, I had to go the other way around by getting all DOM objects with an id and looking for globals that match them.
FYI, you asked about strict mode in your question. strict mode only applies to a given scope of code so there would not be any way to cause it to affect the way the global namespace was set up. To affect something like this, it would have to be something at the document level before the document was parsed like a DOCTYPE option or something like that.
Caveats with this function.
Run it before you create any of your own globals or don't create any of your own globals with the same name as the ID or name attribute that also point to that DOM object.
This is a one-time shot, not continuous. If you dynamically create new DOM objects, you would have to rerun this function to clear any new globals that might have been made from the new DOM objects.
The globals are set to undefined which is slightly different than if they were never there in the first place. I can't think of a programming case where it would really matter, but it isn't identical. Unfortunately, you can't delete global variables.

What is "debugger" in a lexical sense?

I just discovered the debugger keyword or whatever it is for JavaScript development, and I'm not clear what it is. Certainly it's not an expression, it has no value. But do I need to put a semi-colon after it? What is it defined as part of? I mean, it's technically like an addition to the language in the chrome runtime, isn't it?
(I know what it does, I just don't know the details of its implementation and how I would explain its lexical nature to someone else.)
It's actually described in ES5 standard - and yes, it's a statement:
Syntax
DebuggerStatement :
debugger;
Semantics
Evaluating the DebuggerStatement production may allow an
implementation to cause a breakpoint when run under a debugger. If a
debugger is not present or active this statement has no observable
effect.
It is evaluated as follows:
If an implementation defined debugging facility is available and enabled, then
Perform an implementation defined debugging action.
Let result be an implementation defined Completion value.
Else
Let result be (normal, empty, empty). Return result.
As a sidenote, most modern browsers - not only Chrome - support this functionality.

How can I prove that my JavaScript files are in the scope of a specific JS or ECMA version?

Let's say you would get a bunch of .js files and now it is your job to sort them into groups like:
requires at least JavaScript 1.85
requires at least E4X (ECMAScript 4 EX)
requires at least ECMAScript 5
or something like this.
I am interested in any solution, but especially in those which work using JavaScript or PHP. This is used for creation of automated specifications, but it shouldn't matter - this is a nice task which should be easy to solve - however, I have no idea how and it is not easy for me. So, if this is easy to you, please share any hints.
I would expect something like this - http://kangax.github.com/es5-compat-table/# - just not for browsers, rather for a given file to be checked against different implementations of JavaScript.
My guess is, that each version must have some specifics, which can be tested for. However, all I can find is stuff about "what version does this browser support".
PS: Don't take "now it is your job" literally, I used it to demonstrate the task, not to imply that I expect work done for me; while in the progress of solving this, it would be just nice to have some help or direction.
EDIT: I took the easy way out, by recquiring ECMAScript 5 to be supported at least as good as by the current FireFox for my projekt to work as intendet and expected.
However, I am still intereseted in any solution-attemps or at least an definite answer of "is possible(, with XY)" or "is not possible, because ..."; XY can be just some Keyword, like FrameworkXY or DesignPatternXY or whatever or a more detailed solution of course.
Essentially you are looking to find the minimum requirements for some javascript file. I'd say that isn't possible until run time. JavaScript is a dynamic language. As such you don't have compile time errors. As a result, you can't tell until you are within some closure that something doesn't work, and even then it would be misleading. Your dependencies could in fact fix many compatibility issues.
Example:
JS File A uses some ES5 feature
JS File B provides a shim for ES5 deficient browsers or at least mimics it in some way.
JS File A and B are always loaded together, but independently A looks like it won't work.
Example2:
Object.create is what you want to test
Some guy named Crockford adds create to Object.prototype
Object.create now works in less compatible browsers, and nothing is broken.
Solution 1:
Build or find a dependency map. You definitely already have a dependency map, either explicitly or you could generate it by iterating over you HTML files.
Run all relevant code paths in environments with decreasing functionality (eg: ES5, then E4X, then JS 1.x, and so forth).
Once a bundle of JS files fail for some code path you know their minimum requirement.
Perhaps you could iterate over the public functions in your objects and use dependency injection to fill in constructors and methods. This sounds really hard though.
Solution 2:
Use webdriver to visit your pages in various environments.
Map window.onerror to a function that tells you if your current page broke while performing some actions.
On error you will know that there is a problem with the bundle on the current page so save that data.
Both these solutions assume that you always write perfect JS that never has errors, which is something you should strive for but isn't realistic. This might; however, provide you with some basic "smoke testing" though.
This is not possible in an exact way, and it also is not a great way of looking at things for this type of issue.
Why its not possible
Javascript doesn't have static typing. But properties are determined by the prototype chain. This means that for any piece of code you would have to infer the type of an object and check along the prototype chain before determining what function would be called for a function call.
You would for instance, have to be able to tell that $(x).bind() o $(x).map are not making calls to the ecmascript5 map or bind functions, but the jQuery ones. This means that you would really have to parse out the whole code and make inferences on type. If you didn't have the whole code base this would be impossible. If you had a function that took an object and you called bind, you would have no idea if that was supposed to be Function.prototype.bind or jQuery.bind because thats not decided till runtime. In fact its possible (though not good coding practice) that it could be both, and that what is run depends on the input to a function, or even depends on user input. So you might be able to make a guess about this, but you couldn't do it exactly.
Making all of this even more impossible, the eval function combined with the ability to get user input or ajax data means that you don't even know what types some objects are or could be, even leaving aside the issue that eval could attempt to run code that meets any specification.
Here's an example of a piece of code that you couldn't parse
var userInput = $("#input").val();
var objectThatCouldBeAnything = eval(userInput);
object.map(function(x){
return !!x;
});
There's no way to tell if this code is parsing a jQuery object in the eval and running jQuery.map or producing an array and running Array.prototype.map. And thats the strength and weakness of a dynamically typed language like javascript. It provides tremendous flexibility, but limits what you can tell about the code before run time.
Why its not a good strategy
ECMAScript specifications are a standard, but in practice they are never implemented perfectly or consistently. Different environments implement different parts of the standard. Having a "ECMAScript5" piece of code does not guarantee that any particular browser will implement all of its properties perfectly. You really have to determine that on a property by property basis.
What you're much better off doing is finding a list of functions or properties that are used by the code. You can then compare that against the supported properties for a particular environment.
This is still a difficult to impossible problem for the reasons mentioned above, but its at least a useful one. And you could gain value doing this even using a loose approximation (assuming that bind actually is ecmascript5 unless its on a $() wrap. Thats not going to be perfect, but still might be useful).
Trying to figure out a standard thats implemented just isn't practical in terms of helping you decide whether to use it in a particular environment. Its much better to know what functions or properties its using so that you can compare that to the environment and add polyfills if necessary.

Steps to migrate a project to using "strict mode"?

What are some things I must verify before taking an existing code base and converting it to Strict Mode?
The project is a website that is designed to run on all browsers from IE 8 and above, and doesn't have a lot of unit tests or a js linter continuous integration setup at this point.
What are some language features to look out for, that our own code, or libraries that we use might be using, that will silently break if I turn on strict mode?
Is there a code analysis process that can look at my whole project, and point out the specific pitfalls from this migration?
Any particular browsers I should be worried about? (Well, I guess IE 8 is the usual suspect ... but what exactly to look for in IE's 8 support, or lackthereof, of strict mode?)
If I'm not looking for raw performance, but first at avoiding bugs ... is strict mode a cost effective way to help early bug detection?
The one bit of strict code that I violate most is the strict delete operator.
delete someobject.someproperty throws an error if someobject.someproperty is not defined,
while in 'normal' code it deletes the property if it exists, and carries on without an error if it doesn't.
It's easy to fix-
if('someproperty' in someobject) delete someobject.someproperty;
I liked the old way, but things change. Some people hate giving up arguments.callee...
You can avoid prototype chaining by changing the code as follows:
if (someObject.hasOwnProperty("someProperty")) {
delete someObject.someProperty;
}

Automatically created variables from ids in JS? [duplicate]

This question already has answers here:
Do DOM tree elements with IDs become global properties?
(5 answers)
Closed 5 years ago.
Just today after a couple of years of javascript programming I came across something that left me startled. Browsers create objects for every element with an id. The name of the object will match the id.
So if you have:
<div id ="box"></div>
You can do:
alert(box); //[object HTMLDivElement]
Without first assigning anything to that variable. See the demo.
This for some reason seems to be in the standards even though it can break the code in some cases. There is an open bug to end this behavior but I'm more interested in getting rid of it now.
Do you guys know if there is a way to disable this (strict mode maybe)? Am I giving this too much importance? Because it certainly seems like a bad idea. (It was introduced by IE to give you a hint).
Update: It seems FF only does this in quirks mode. Other browsers like IE6+ and Chrome do it right off the bat.
ECMAScript 5 strict should help with this as you cannot use undeclared variables. I'm not sure which browsers currently support strict mode but I know Firefox 4 does.
The HTML spec you linked mentions a proposal to reduce pollution of the global scope by limiting this behavior to quirks-only.
I don't know if this feature is in the original spec but I do expect it to be removed, prohibited or otherwise nullified in subsequent versions of ECMAScript. ES6 will be based on ES5 strict.
JavaScript has many features that make it easier to use for beginners and novices, I suspect this is one such feature. If you're a professional and you want quality code use "use strict"; and always JSLint your code. If you use these guidelines this feature should never bother you.
Here is a useful video about ES5 courtesy of YUI Theater (it's already 2 years old though, but still relevant currently as there is no ES6 yet).
I don't think this is much of a big deal. It seems messy especially to those of us who think about global namespace pollution and conflicts, but in practice it doesn't really cause a problem.
If you declare your own global variable, it will just override anything the browser created for you so there's not really any conflict. The only place I could see it potentially causing a problem is if you were testing for the existence of a global declaration and an "auto" global based on an object ID got in the way of that and confused you.
In practice, I've never seen this to be a problem. But, I'd agree it seems like something they should get rid of or allow you to turn off.
Yes most browsers do this but then again like you said some don't (firefox) so don't count on it. It's also easy to overwrite these variables in js, I can imagine something like container might be overwritten right of the bat by someone using that variable without declaring it first.
There is no way to turn this of in chrome afaik but even then it might be a hassle to figure this out and fix it for all browsers.
Don't give it too much importance, but beware of it. This is one of those reasons why you would evade the global scope for variables.
For the sake of completion, these browsers definitly do it by default: Chrome, IE9 & compat, Opera
Update: Future versions of ECMAScript might include an option of some sort since yes discussion is going on, but that will not fix the 'problem' in older browsers.
I don't think there's a way to disable it, but you don't need to put much importance to it. If you are afraid of unpredictable bugs, you could avoid them by using JSHint or JSLint. They will help you avoid mistakes. For example, they will warn you if you use an undeclared variable.
The problem here is that the global scope has objects defined in it at runtime by the browser, and you would like to prevent these definitions from interfering with your code. I'm not aware of a way to turn off this behaviour, but I do have two workarounds for you:
1) As suggested in the article you linked to, you can work around this by ensuring that you define each variable before you use it. I would achieve this by running my code through JSLint, which warns about this sort of thing (in addition to a bunch of other common errors).
2) However, since it's possible to forget to run your code through JSLint, you might prefer a step in the tool chain that you can't forget. In that case, have a look at CoffeeScript - it's a langauge very similar to javascript that you compile into javascript before use, and it will insert the correct var definitions for you. In fact, I suspect that you can't write code that relies on the automatic element variable creation using CoffeeScript.
This is what I've been able to come up with to remove global variables that are automatically created for DOM objects with an ID value:
function clearElementGlobals() {
function clearItem(iden, item) {
if (iden && window[iden] && (window[iden] === item)) {
window[iden] = undefined;
}
}
var list = document.getElementsByTagName("*");
for (var i = 0, len = list.length; i < len; i++) {
var item = list[i];
clearItem(item.id, item);
clearItem(item.name, item);
}
}
This gets a list of all objects in the page. It loops through looking for ones with an id value and when there's an id value and a global variable exists for it and that global variable points to that DOM object, that global variable is set to undefined. As it turns out browsers also do this same auto-global for some types of tags with a name attribute (like form elements) so we clear those too.
Of course, this code can't know whether your own code makes a global variable with the same name as the id so it would obviously be best to either not do that in your own code or call this function before your global variables are initialized.
Unfortunately, you cannot delete global variables in javascript so setting it to undefined is about the best that can be done.
FYI, I tried doing this the other way around where you enumerate global variables looking for variables that are an instance of HTMLElement and that have a name that matches the id of the element they point to, but I couldn't find a reliable way to enumerate global variables. In Chrome, you can't enumerate them on the window object even though you can access them through the window object. So, I had to go the other way around by getting all DOM objects with an id and looking for globals that match them.
FYI, you asked about strict mode in your question. strict mode only applies to a given scope of code so there would not be any way to cause it to affect the way the global namespace was set up. To affect something like this, it would have to be something at the document level before the document was parsed like a DOCTYPE option or something like that.
Caveats with this function.
Run it before you create any of your own globals or don't create any of your own globals with the same name as the ID or name attribute that also point to that DOM object.
This is a one-time shot, not continuous. If you dynamically create new DOM objects, you would have to rerun this function to clear any new globals that might have been made from the new DOM objects.
The globals are set to undefined which is slightly different than if they were never there in the first place. I can't think of a programming case where it would really matter, but it isn't identical. Unfortunately, you can't delete global variables.

Categories