Previously I analyzed ECMAScript 5’s Object and Property system. This is a huge new aspect of the language and deserved its special consideration.
There are a number of other new features and APIs that need attention, as well. The largest of which are Strict Mode and native JSON support.
Strict Mode
Strict Mode is a new feature in ECMAScript 5 that allows you to place a program, or a function, in a “strict” operating context. This strict context prevents certain actions from being taken and throws more exceptions (generally providing the user with more information and a tapered-down coding experience).
Since ECMAScript 5 is backwards-compatible with ECMAScript 3, all of the “features” that were in ECMAScript 3 that were “deprecated” are just disabled (or throw errors) in strict mode, instead.
Strict mode helps out in a couple ways:
- It catches some common coding bloopers, throwing exceptions.
- It prevents, or throws errors, when relatively “unsafe” actions are taken (such as gaining access to the global object).
- It disables features that are confusing or poorly thought out.
Most of the information about strict mode can be found in the ES5 specification [PDF] on page #235.
It should be noted that ECMAScript 5’s strict mode is different from the strict mode available in Firefox (which can be turned on by going to about:config and enabled javascript.options.strict). ES5’s strict mode complains about a completely different set of potential errors (whereas Firefox’s existing strict mode tries to enforce some good practices, only).
How do you enable strict mode?
Simple. Toss this at the top of a program to enable it for the whole script:
"use strict";
Or place it within a function to turn on strict mode only within that context.
function imStrict(){ "use strict"; // ... your code ... }
Note the syntax that’s used to enable strict mode (I love this!). It’s simply a string in a single statement that happens to contain the contents “use strict”. No new syntax is introduced in order to enable strict mode. This is huge. This means that you can turn strict mode on in your scripts – today – and it’ll have, at worst, no side effect in old browsers.
As you may note from the examples here and in the previous post there are virtually no new syntax additions or changes to the language in ECMAScript 5. This means that you can write your ES5 scripts in a manner that will be able to gracefully degrade for older useragents – something that wasn’t possible with ECMAScript 4. The way in which strict mode is enabled is a great illustration of that point in practice.
A neat aspect of being able to define strict mode within a function is that you can now define complete JavaScript libraries in a strict manner without affecting outside code.
// Non-strict code... (function(){ "use strict"; // Define your library strictly... })(); // Non-strict code...
A number of libraries already use the above technique (wrapping the whole library with an anonymous self-executing function) and they will be able to take advantage of strict mode very easily.
So what changes when you put a script into strict mode? A number of things.
Variables and Properties
An attempt to assign foo = "bar";
where ‘foo’ hasn’t been defined will fail. Previously it would assign the value to the foo property of the global object (e.g. window.foo
), now it just throws an exception. This is definitely going to catch some annoying bugs.
Any attempts to write to a property whose writable attribute is set to false, delete a property whose configurable attribute is set to false, or add a property to an object whose extensible attribute is set to false will result in an error (these attributes were discussed previously). Traditionally no error will be thrown when any of these actions are attempted, it will just fail silently.
Deleting a variable, a function, or an argument will result in an error.
var foo = "test"; function test(){} delete foo; // Error delete test; // Error function test2(arg) { delete arg; // Error }
Defining a property more than once in an object literal will cause an exception to be thrown
// Error { foo: true, foo: false }
eval
Virtually any attempt to use the name ‘eval’ is prohibited – as is the ability to assign the eval function to a variable or a property of an object.
// All generate errors... obj.eval = ... obj.foo = eval; var eval = ...; for ( var eval in ... ) {} function eval(){} function test(eval){} function(eval){} new Function("eval")
Additionally, attempts to introduce new variables through an eval will be blocked.
eval("var a = false;"); print( typeof a ); // undefined
Functions
Attempting to overwrite the arguments object will result in an error:
arguments = [...]; // not allowed
Defining identically-named arguments will result in an error function( foo, foo ) {}
.
Access to arguments.caller
and arguments.callee
now throw an exception. Thus any anonymous functions that you want to reference will need to be named, like so:
setTimeout(function later(){ // do stuff... setTimeout( later, 1000 ); }, 1000 );
The arguments
and caller
properties of other functions no longer exist – and the ability to define them is prohibited.
function test(){ function inner(){ // Don't exist, either test.arguments = ...; // Error inner.caller = ...; // Error } }
Finally, a long-standing (and very annoying) bug has been resolved: Cases where null or undefined is coerced into becoming the global object. Strict mode now prevents this from happening and throws an exception instead.
(function(){ ... }).call( null ); // Exception
with(){}
with(){}
statements are dead when strict mode is enabled – in fact it even appears as a syntax error. While the feature was certainly mis-understood and possibly mis-used I’m not convinced that it’s enough to be stricken from the record.
The changes made in ECMAScript 5 strict mode are certainly varied (ranging from imposing stylistic preferences, like removing with statements, to fixing legitimately bad language bugs, like the ability to redefine properties in object literals). It’ll be interesting to see how people begin to adopt these points and how it’ll change JavaScript development.
All that being said, I’m fairly certain that jQuery is ES5-Strict compatible right now. Once an implementation of the language is made available (so that that premise may be tested) I’ll happily switch jQuery over to working exclusively in strict mode.
JSON
The second major feature of the language is the addition of native JSON support to the language.
I’ve been championing this move for a long time and I’m glad to see it finally arrive in a specification.
In the meantime PLEASE start migrating your JSON-using applications over to Crockford’s json2.js. It is fully compatible with the ECMAScript 5 specification and gracefully degrades if a native (faster!) implementation exists.
In fact, I just landed a change in jQuery yesterday that utilizes the
JSON.parse
method if it exists, now that it has been completely specified.
There are two primary methods for handling JSON: JSON.parse
(which converts a JSON string into a JavaScript object) and JSON.stringify
(which convert a JavaScript object into a serialized string).
JSON.parse( text )
Converts a serialized JSON string into a JavaScript object.
var obj = JSON.parse('{"name":"John"}'); // Prints 'John' print( obj.name );
JSON.parse( text, translate )
Use a translation function to convert values or remove them entirely.
function translate(key, value) { if ( key === "name" ) { return value + " Resig"; } } var obj = JSON.parse('{"name":"John","last":"Resig"}', translate); // Prints 'John Resig' print( obj.name ); // Undefined print( obj.last );
JSON.stringify( obj )
Convert an object into a serialized JSON string.
var str = JSON.stringify({ name: "John" }); // Prints {"name":"John"} print( str );
JSON.stringify( obj, ["white", "list"])
Serialize only a specific white list of properties.
var list = ["name"]; var str = JSON.stringify({name: "John", last: "Resig"}, list); // Prints {"name":"John"} print( str );
JSON.stringify( obj, translate )
Serializes the object using a translation function.
function translate(key, value) { if ( key === "name" ) { return value + " Resig"; } } var str = JSON.stringify({"name":"John","last":"Resig"}, translate); // Prints {"name":"John Resig"} print( str );
JSON.stringify( obj, null, 2 )
Adds the specified number of spaces to the output, printing it evenly.
var str = JSON.stringify({ name: "John" }, null, 2); // Prints: // { // "name": "John" // } print( str );
JSON.stringify( obj, null, "\t" )
Uses the specified string to do the spacing.
var str = JSON.stringify({ name: "John" }, null, "\t"); // Prints: // {\n\t"name": "John"\n} print( str );
Additionally, a few new generic methods have been added to some of the base objects but, frankly, they aren’t that interesting. The results from String, Boolean, and Number are just equivalent to calling .valueOf()
and the result from Date is equivalent to calling .toISOString()
// Yawn... String.prototype.toJSON Boolean.prototype.toJSON Number.prototype.toJSON Date.prototype.toJSON
.bind()
A welcomed addition to the language is a built-in .bind()
method for enforcing the context of a function (virtually identical to Prototype’s .bind implementation).
Function.prototype.bind(thisArg, arg1, arg2....)
Enforces the ‘this’ of the specified function to a specific object – and passing in any specified arguments.
var obj = { method: function(name){ this.name = name; } }; setTimeout( obj.method.bind(obj, "John"), 100 );
Considering how long this function (and its equivalents) have been around it’s a welcome addition to the language.
Date
Dates are now capable of both parsing and outputting ISO-formatted dates. Thank goodness, about time. rimshot
The Date constructor now attempts to parse the date as if it was ISO-formatted, first, then moves on to the other inputs that it accepts.
Additionally, date objects now have a new .toISOString()
method that outputs the date in an ISO format.
var date = new Date("2009-05-21T16:06:05.000Z"); // Prints 2009-05-21T16:06:05.000Z print( date.toISOString() );
.trim()
A native, built-in, .trim()
is now included for strings. Works identically to all the other trim methods out there – with the potential to possibly work faster.
Steven Levithan has discussed the trim method in great depth.
Array
The JavaScript Array Extras that’ve been around for, what seems like, forever are finally formally specified. This includes the following methods: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce, and reduceRight.
Additionally a new Array.isArray
method is included, providing functionality very similar to the following:
Array.isArray = function( array ) { return Object.prototype.toString.call( array ) === "[object Array]"; };
Altogether I think ECMAScript 5 makes for an interesting package. It isn’t the massive leap that ECMAScript 4 promised but it is a series of respectable improvements that reduces the number of obvious bugs while making the language safer and faster. I’m looking forward to when some implementations start to go public.
Greg (May 22, 2009 at 7:12 am)
I’m not clear on why it’s a good thing that arguments.caller and arguments.callee are deprecated/disabled. Could you explain? I thought they were useful and neither ambiguous nor error-prone.
John Resig (May 22, 2009 at 7:26 am)
@Greg: I did some digging and found a thread where they discuss this issue. It seems like the biggest problem is passing the arguments object to another function, where it is capable of accessing the callee/caller information, without your knowledge. Personally, I’m going to miss
arguments.callee
, I used it in a number of places in my code.Harley Jones (May 22, 2009 at 7:54 am)
@Greg, @John: I’ve been using arguments.caller and arguments.callee to create a stack trace for error handling. Can this be accomplished another way? I suppose I could use a block of code outside the “use script” scope. Is there a “stop strict”?
John Resig (May 22, 2009 at 8:00 am)
@Harley: No, it doesn’t appear as if there’s any way to break out of strict mode, once you’re in it. Your specific use case seems fairly safe since it’s a library that would be included during the debug process, so you could ask them to disabled strict mode explicitly.
Kevin van Zonneveld (May 22, 2009 at 8:09 am)
Thanks for the heads up John, this looks awesome!
Joe Larson (May 22, 2009 at 8:16 am)
I keep hearing various versions of this: “No new syntax is introduced in order to enable strict mode. This is huge. This means that you can turn strict mode on in your scripts – today – and it’ll have, at worst, no side effect in old browsers.”.
Except that, as soon as I start writing code that expects to be running in a strict context, that code may not fail in a ES3 browser, but it sure won’t do what I want. Some of the degradation will be graceful– inability to lock down properties, etc, we have to live with that today. Other degradation is not so graceful– for example I can’t write code that relies on the enumerable setting for a property being on or off. Which means I will either have to say “only ES5 browsers” or have two sets scripts or have one set of scripts with lots of switches. This seems painful. What am I missing?
John Resig (May 22, 2009 at 8:26 am)
@Joe Larson: I think you misinterpreted what I said – I didn’t say that all ECMAScript 5 code is backwards compatible to ECMAScript 3 – just that the syntax is backwards compatible. You’ll be able to use feature detection to determine if the newly-added features work as you expect them to and be able to provide a graceful fallback if they don’t.
Now, if there was absolutely no new logic introduced in ES5 then that would be a sad language update indeed – going nowhere very slowly.
Having two versions of a script seems fine to me, if you’re taking explicit advantage of some of the advanced features (like
Object.defineProperty
) AND you MUST continue to support all browsers – since any sort of “graceful” degradation there simply isn’t possible – you’d be under an inferior runtime.Strict mode is one thing that we can start to use immediately in all browsers (especially since it’s mostly useful as a debugging tool). We’ll have to wait a bit before we can use the others everywhere, as well. That being said – for those working in a single environment (developing Firefox extensions, writing ActionScript, iPhone applications, or other single-runtime applications) will receive an immediate, and large, benefit from this language update.
Joe Larson (May 22, 2009 at 8:38 am)
John — ok, thanks for the clarification. It just seems like the language being used keeps alluding to some kind of magical backwards compatibility, and as you rightly say, that is sort of nonsensical for a real language upgrade. As long as the pain is acknowledged, that’s fine, two scripts is worth it. And hopefully we don’t have to live with that for long, or at all in some circumstances.
Andrea Giammarchi (May 22, 2009 at 9:16 am)
arguments.callee … for god sake do not touch it!
I cannot imagine a global scope where every single function will persist causing naming conflicts everywhere because of this pointless choice!
setTimeout(function a(){}, 1);
alert(this.a);
In every Internet Explorer above code will create the CHAOS … it seems that everything is Douglas Crockford choice ( arguments.callee as an error ) and YUI Compressor ( with( … ) ) these two things will make backward compatibility in strict mode a nightmare.
Finally, again vice-versa project, Array is now 1.8 almost full specs.
Mariusz Nowak (May 22, 2009 at 9:20 am)
What is your recommended way of implementation this ECMAScript 5 features in ECMAScript 4 engines? Should libraries edit native objects and set those methods on them e.g.:
if (!Array.isArray) {
Array.isArray = function (obj) { ... }
}
Or maybe we should keep away from that. Some other js code on webpage may do some sniffing based on existence of those methods. If we put them in with our library then “other code” may not work as expected – this is of course rare case and doesn’t say much good about “other code” but still – should we care about that ?
How do you deal with that in jQuery ?
Nick (May 22, 2009 at 9:24 am)
I may well be missing something but what is the difference between .bind() and .call()?
TNO (May 22, 2009 at 9:24 am)
@Greg and John Resig:
The arguments object in general is being set up to be removed from the language and replaced with named, optional and rest parameters instead.
arguments.callee can be replaced with a named function literal:
var foo = function self(){
...
self()
}
“self” will exist only in the scope of that function, not globally, so this will be shorter code that arguments.callee.
As for arguments.caller, I don’t believe that was ever part of the spec anyway… Plus it seems that the next version (after ECMAScript 5) should provide separate stack tracing functionality (possibly on the Error object)
Andrea Giammarchi (May 22, 2009 at 9:35 am)
@Mariusz Nowak, if Array.isArray and others methods are full specs there is not a single problem to use it with or without sniffing. I mean, an indexOf is an indexOf, it is extremely useful and if there is a sniff, will be 99% of the time to implement it if not present.
@Nick, bind prevent injected scope or global one, you can pre specify a scope and call the function as is, without even attaching it to an object.
var a = {doStuff:function(){alert(this.name)}, name:"a"};
var b = {name:"b"};
var c = a.doStuff.bind(b);
c(); // "b"
@TNO, that will break in every Internet Explorer because as soon as you create a function with a name this will persist with its name in the scope. arguments.callee has nothing bad at all, I cannot spot a single reason to remove it or make it deprecated in strict mode.
Harley Jones (May 22, 2009 at 9:37 am)
I think the argument was well made on the mailing list that arguments.callee.caller is NECESSARY for building a stack-trace. And I do NOT think this is a use-case that is segregated to “debug-mode” only. When wacky stuff happens in the field (in front of the customer), I need all the information I can get. The customer is rarely capable of describing the conditions and situation that brought on the exception. A thorough stack-trace is probably the best tool for debugging this type of thing.
Of course, if all browser vendors supported window.onerror and Error.prototype.stack, we’d have a fallback. But Firefox offers “stack”, Opera offers “stacktrace”, and they’re inconsistent. Only Firefox and IE support window.onerror, and again, they’re inconsistent. Some browsers expose <SCRIPT> loading errors, and some browsers expose <IMG> loading errors.
I understand the security concerns involved in arguments.callee; and I think that should be examined closely. But, it’s my opinion that JS/browser exception handling sucks pretty bad. Removing arguments.callee.caller is a big step in the WRONG direction.
Andrea Giammarchi (May 22, 2009 at 9:59 am)
@Harley Jones, I do not get security problems at all about callee …
Harley Jones (May 22, 2009 at 10:12 am)
In short, it’s the Principle of Least Authority (POLA). Who’s got access to your code? And we’re not just talking about the ability to view your code. If your code calls mine, I can use arguments.callee.caller to view/modify your code. Likewise, I can use arguments.callee.caller.arguments to view/modify your arguments.
That’s a pretty severe security risk. My applications run within a secured intranet and I have control over the scripts being executed. So, it’s not a large concern for me. However, what’s to stop a foolish user from downloading malware that installs a GreaseMonkey-type app or an ActiveX that can do untold damage?
Of course, that type of argument falls apart (in my opinion). Afterall, what’s to stop a foolish user from doing anything that’s, well, foolish?
Like I said, I understand the “concern.” But, that concern might be a molehill that’s been turned into a mountain.
TNO (May 22, 2009 at 10:27 am)
@Andrea Giammarchi:
Surely your argument isn’t to avoid implementing new features because IE doesn’t support it right now? The JScript team has stated they plan to follow the spec on this. In the link John Resig has posted in his comment above, you can read the same discussion. If you dislike it and have a better idea, no one is stopping you from posting your concerns on the mailing list. Shooting the messenger won’t get you anywhere….
Andrea Giammarchi (May 22, 2009 at 10:37 am)
@Harley Jones, still, I do not get concrete applications of these problems … at all. I do not eval stuff before I use arguments, usually I eval at the end of a funciton execution or async (readyState === 4, what can you do that bad? and what if I eval outside the function scope as we almost all do?)
If somebody can inject code inside my function, he can change the function itself (think inside a setTimeout) so security problems are not solved at all unless everything become sealed/frozen. In any case, I am talking about callee, not caller, just arguments.callee, if you have that you will not break every Internet Explorer version with potentially hundreds of function name conflicts in the global scope. This is my point. About with, well, if you do not know what you are doing, it cannot be a language spec problem. with is a problem only for YUI Compressor and hilariously enough, with with you can save a lot of characters:
with(document.body){
appendChild(node);
attachEvent("something", function bleah(){});
removeChild(otherNode);
with(firstChild){
parentNode.removeChild(anotherNode);
};
};
where is the problem here exactly? don’t get this as well, but I prefer “no with” rather than “no arguments.callee”
@TNO, I am not shooting, I am just trying to understand your points to eventually open a better post in ML. All this ES5 idea was to avoid drastic changes over what we have so far but these two things will create a lot of compatibility problems. That’s it.
@TNO, John, sorry I did not see your comment with the link. Going there to talk about it.
Jeffrey Gilbert (May 22, 2009 at 10:58 am)
Out of curiosity, have you heard if there will be anything like the suggested typecasting support that got dropped from the proposed ECMA4 in future iterations or is that just plain off the dev board due to legacy needs?
Off topic, but jetpack looks awesome with JQuery built in. I can’t wait to mess with that since it’s like grease monkey + a supercharger. Is that the results of fuel or is that another story all together? I haven’t gotten into xul dev at all.
Chris Wanstrath (May 22, 2009 at 11:06 am)
Ahhh this is freaking sweet, I can’t wait to start using some of this stuff.
Thanks for the posts summarizing!
John Resig (May 22, 2009 at 11:23 am)
@Nick: .call() immediately executes the function with a specific ‘this’ set – whereas .bind() *returns* a function that, when called, will have a specific ‘this’ set. Using .bind() you can pass a function some place else, where it will be executed at a later time, and ensure that its ‘this’ will remain intact.
@Jeffrey Gilbert: I haven’t heard anything yet about the features of the next version of ECMAScript, but considering how cautious the ECMAScript committee is being now, with new features, I think it’s very doubtful that we’ll see the type system from ECMAScript 4.
asf (May 22, 2009 at 11:57 am)
should the strict thing not be versioned from the start? “use strict(1.0)”; or whatever
schmichael (May 22, 2009 at 12:07 pm)
I’m with asf, what happens when ECMAScript 6 comes out? Will the meaning of “use strict”; change or will it be augmented with a version?
As a Python coder I couldn’t help but think of a couple lines from the Zen of Python:
Explicit is better than implicit.
In the face of ambiguity, refuse the temptation to guess.
Seems like “use strict”; implicitly means “use strict mode according to ECMAScript 5”.
David Smith (May 22, 2009 at 12:33 pm)
Andrea Giammarchi: Many of these restrictions make it possible to have faster javascript engines. The mere existence of ‘eval’ and the arguments object disables or greatly increases the complexity of certain optimizations (for example, consider that Number.prototype.toString = eval; is valid js. It’s very difficult to tell when a function with one String argument will suddenly change everything, and as such it’s very difficult to make optimizations that require reordering code past function calls).
As for ‘with’, http://twitter.com/ohunt/status/1812802546 sums it up better than I can, and from someone with far more expertise than me.
TNO (May 22, 2009 at 12:42 pm)
@Jeffrey Gilber, @John Resig:
Mark Miller mentioned it to me a couple days ago on Ajaxian that a type system is still on the table for post ES5. There are a few issues left to hash out but we can at least see what the current direction is:
http://wiki.ecmascript.org/doku.php?id=strawman:types
Dave (May 22, 2009 at 12:51 pm)
@Andrea: Requiring a name for functions rather than using arguments.callee will cause global namespace pollution, I agree. In JScript I seem to recall that even nested functions pollute the global name space so it would be tough to write backwards-compatible code:
http://nedbatchelder.com/blog/200812/internet_explorer_mystery_1376.html
@Harley: It sure would be nice if they could tackle the error reporting stuff and get it right for version 5, because I use it heavily as well.
Elijah Grey (May 22, 2009 at 2:38 pm)
Does
"use strict";
stay confined within curly braces {} (labeled or otherwise) code blocks too? For example:some_code_block: {
"use strict";
let a = 0;
with ({a:1}) {
print(a);
}
}
John Resig (May 22, 2009 at 2:46 pm)
@asf, schmichael: I assume that once the semantics of “use strict” is changed there’s going to be changes to the underlying syntax of the language, as well – and when that happens developers will have to opt in to the new version of the language anyway (e.g. <script type=”application/ecmascript+6.0″>, or some such).
@Elijah: No, the strict mode can only be scoped to functions and entire applications, not blocks.
Michael Schurter (schmichael) (May 22, 2009 at 2:58 pm)
@John Resig: I think what asf and I are wondering is wouldn’t it be better to have a standard way of specifying the preferred strictness level to make backwards compatibility in the future easier. So “use strict 5”; in an ECMAScript 6 parser would *not* enable strict mode.
Perhaps you could conditionally enable “use strict”?
if (ecmascript.version <= 5) "use strict";
Both of my suggestions assumes that each ECMAScript implementation only needs to implement 2 modes: strict and not strict. We just need a way to tell the engine what definition of "strict" our code is expecting.
Mark Caudill (May 22, 2009 at 3:29 pm)
I documented most of the changes to JavaScript (through ECMA 5). It can be really handy when you’re looking into the future for how your framework/site/library should act.
Also worth a read on the new features:
http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/
John Resig (May 22, 2009 at 4:07 pm)
@Michael: That seems reasonable to me – you should bring that point up to the es-discuss list!
@Mark: I ran across your page but I didn’t find it immediately useful (or, at least, it was less useful than just reading the specification directly). For example all the new Object methods are really quite tricky and difficult to grasp as are all the particulars of strict mode. Thanks for pulling to together, though!
Matt Sherman (May 22, 2009 at 7:48 pm)
Great stuff. One might also hope that browsers will take advantage of “use strict” to optimize performance:
http://clipperhouse.com/blog/post/Javastrict.aspx
zimbatm (May 23, 2009 at 4:27 am)
For ES5, “use strict”; is ES3-deprecated features
For ES6 ? Will we have to “use really-strict”; ?
zimbatm (May 23, 2009 at 4:32 am)
All those “security” features are clearly for the Caja people. Why lock down the entire interpreter when what they really want is secure context where they can execute code in ?
Marius Gundersen (May 23, 2009 at 8:23 am)
What happened to all the AS2/3 features? Some of them should be easy to implement without breaking backwards compatability, like classes for example.
Andrea Giammarchi (May 23, 2009 at 8:57 am)
If anybody is with with me, or interested to know a possible solution about this callee stuff, I wrote a post describing the problem and suggesting a snippet. Regards
John Resig (May 23, 2009 at 9:23 am)
@zimbatm: I wouldn’t really call strict mode “locking down the entire interpreter” – it’s just making a bunch of nasty loopholes no-longer possible (which is how it should be) – plus it’s not really “for the Caja people” it’s more for people who care about enforcing some level of security in ECMAScript/JavaScript.
@Marius: We’ll probably see some of them in the next version of ECMAScript (not sure what version that’ll be – maybe 6?). Unfortunately even something as “easy to implement” as classes isn’t easy to add to the language. It requires new grammar added to the parsers and it requires new logic to be added to the actual construction of classes. At least for now, I’m glad that they’ve added in these incremental updates, from which future features can be added.
RogerV (May 23, 2009 at 1:04 pm)
The breaking away from adopting ActionScript3 enhancements into mainstream ECMAScript was purely about Microsoft looking to do a little log-jamming to Adobe’s on-going success with Flex/FlayPlayer/AIR.
I really like the way in AS3 I can program with classes and interfaces that have compile-time static type checking, and yet where advantageous, I can still do dynamic JavaScript-like objects at runtime that a composed or augmented via prototype, etc. Plus JavaScript-style closures are available for use even in the static type checked code. Then there’s the package namespace for better module encapsulation and code sharing re-usability. Etc., etc.
Sigh…politics triumphed as usual, though.
TNO (May 23, 2009 at 2:31 pm)
@RogerV:
What evidence do you have of this claim? According to the mailing list, this was not what happened. Also, classes and types will be in the post ES5 standard.
TNO (May 23, 2009 at 2:39 pm)
@Andrea Giammarchi:
So, your primary argument against this that this is a bad idea because IE doesn’t support it yet?
Andrea Giammarchi (May 23, 2009 at 6:16 pm)
@TNO … it is not about “yet”, it is not a method you can implement, it is an entirely different way to write entire applications with lambdas. I’d love to see IE disappear from the browsers panorama tonight but I am a web developer and I have to face the reality. If all this stuff is for 2036 then I would not complain at all, but since I know WebKit, Chrome, Opera, and Mozilla guys are truly quick when we talk about new features, I cannot imagine a panorama where web developers have to trap everything in a closure or write twice stuff because IE will never disappear in reasonable time and we would like to write less code, rather than more. The compatibility issue, is the main reason ECMAScript 4 failed … nobody “supported yet” anything … so I miss the point to kill out IE from the panorama … we have to deal with it, even if we would like to avoid it. Only Microsoft can change this situation but it will never do soon. Just my opinion. Regards
TNO (May 23, 2009 at 8:51 pm)
@Andrea Giammarchi:
I’m almost certain this was part of the decision making process, hence why its only strict mode that eliminates callee and not non-strict ES5. Point remains that the arguments object has to go away to fix TCP and other issues mentioned in the thread, and this is the first step in that direction. Its not like we can’t opt-out of strict mode.
Alexander Kellett (May 24, 2009 at 4:05 am)
ahhhhh. at last. removing callee will make optimising javascript much much easier. andrea, would you rather have fast less buggy easier to maintain javascript engines, or support this?
Alex
Andrea Giammarchi (May 24, 2009 at 5:02 am)
@Alexander, to be honest I am pretty much happy with V8 Engine and SquirrelFish Extreme performances. Google O3D can compile internally C++ code, if we need extreme performances we are using the wrong programming language. Is all this stuff about canvas or what? I rather prefer a fully strict ActionScript 3 sandbox possibility via Tamarin rather than a dieing JavaScript loosing his malleability beauty to become so fast that people could stop to understand it and write good code cause new features will cover every developer knowledge gap thanks to new amazing performances … hard to say if I want all these performances and change one of the “coolest” programming languages I’ve ever learn. The funny stuff would be an extremely fast language over 10 different APIs from browser vendors. Not sure we are doing it right guys … not sure at all, I though JS problems were different from arguments and callee, maybe I am wrong. Nevermind
Mitchell Lane (May 24, 2009 at 9:38 am)
@Marius: All of the features added to ES5 make conventional classes as you would have them able to be implemented in existing JavaScript. All that’s missing is the syntatic sugar (class Foo { … }), which is sure to follow in a later version, now that the groundwork has been laid out for it.
RogerV (May 24, 2009 at 12:08 pm)
@TNO
Even Wikipedia let comments stand that ECMAScript4 was abandoned due to political reasons: http://en.wikipedia.org/wiki/ECMAScript
Other bloggers have well covered the aftermath of the standards committee meeting when the ECMAScript4 standard got torpedoed:
JavaScript Stalled, AS3 Orphaned – Microsoft to Blame
http://www.gskinner.com/blog/archives/2008/08/javascript_stal.html
Ru Roh! Adobe Screwed By EcmaScript Standards Agreement
http://whydoeseverythingsuck.com/2008/08/ru-roh-adobe-screwed-by-ecmascript.html
Then Dave McAllistar of Adobe posted these comments:
Standards, ECMAScript and representing the past
http://blogs.adobe.com/open/2008/08/blog_entry_dated_81408_715_pm.html
“Unfortunately, as is the case with many standards, the situation became a tug of war. Standards aren’t just about the good of the community; they are also now recognized as competitive advantages. A new standard for ECMAScript thus became mired in a morass of bickering, infighting, and sometimes, out and out name calling; the politics of competition. It became clear that members could not arrive at the consensus needed to allow a decade of advancements to be incorporated into the next generation of ECMAScript.”
Nosredna (May 26, 2009 at 3:46 pm)
I want “caller” more than I want “callee.” It was terribly useful for metaprogramming. But it wasn’t universally supported the way callee was. Kinda surprised callee is leaving us.
TNO (May 26, 2009 at 5:23 pm)
@RogerV:
What do any of your links have to do with your initial, overgeneralized statement?
“The breaking away from adopting ActionScript3 enhancements into mainstream ECMAScript was purely about Microsoft looking to do a little log-jamming to Adobe’s on-going success with Flex/FlayPlayer/AIR.”
If you followed the comments on es-discuss as well as heard some of Brendan Eich’s comments in the open web podcast:
http://openwebpodcast.com/episode-2-brendan-eich-and-arun-ranganathan-on-ecmascript-harmony
You would see that it was an issue of AS3 not being appropriate for the web, not the result of some secret conspiracy in the standardization group.
RogerV (May 26, 2009 at 11:01 pm)
I merely parotted Adobe’s Dave McAllistar’s take – and Adobe was a direct participant in this committee proceedings last year. Dave’s concern revolved around communicating the matter to the folks that develop and use Adobe’s Flash technology. Basically I hold Adobe to be a much better source than yourself as to what actually went down.
If you have a problem with my assessment I suggest you take the matter directly to Dave and the other folks at Adobe. Being steeped in Flex development I know a number of them and they all hold exactly the same opinion on these proceedings.
As a former Microsoft employee, I don’t harbor anti-MS sentiments like so much of the web community does. Is just having worked there and been involved directly in the internal email exchanges that lead to a strategy to embrace and extend Sun’s Java (mid-90’s) to enhance it specifically to Windows development focus, I know first-hand how MS operates mentality-wise. This kind of monkey wrenching is exactly a strategy that I would see the MS execs formulating. The number one driving force you learned when working at MS is to prevail in the market against competitors using tough competitive practices to do it if necessary.
Actually, monkey wrenching Adobe’s aspirations for ActionScript3 becoming adopted as official ECMAScript is very mild compared to other tactics I’m personally aware of.
breton (May 28, 2009 at 9:59 pm)
I’ve been an avid follower of the ecmascript list since the harmony announcement. The oslo meetings was a turning point. Before that, you might have been right, RogerV. Microsoft was pushing hard against the ecmascript 4 efforts, and so was Doug Crockford for his own reasons. Ultimately though, what I saw is that we ended up with Ecmascript 5 because the ecmascript 4 group couldn’t figure out how to make packages and namespaces work without intractable design problems, and simply ran out of time. At the oslo meeting they abandoned ecmascript 4 in favor of ecmascript 3.1, and focused their efforts on that.
There may have been some politics at play at some point, but whether there were politics or not, ecmascript 4 still would have failed regardless, and we’d still be discussing ecmascript 5, with precisely the stripped back featureset we have now. I don’t necessarily buy your interpretatiomn of Adobe’s take, but if it’s accurate it sounds like sour grapes. However, what I read at the time of the Harmony announcement was that adobe is officially OKAY with it, and plans to track Ecmascript 5’s features in actionscript.
breton (May 28, 2009 at 10:14 pm)
With regard to “use strict” versioning, I wouldn’t expect it to be necessary, since “use strict” doesn’t really alter the behavior of the script except to cause it to throw more exceptions. This is similar in function to a built in jslint, a program that does not need versioning since the result of making a program pass jslint is always a valid ecmascript 3 program. I would expect the same with “use strict”, since it will not at any point require the use of any feature that would break older browsers. (it may not forbid them either, but that’s a seperate matter).
breton (May 28, 2009 at 10:17 pm)
“since the result of making a program pass jslint is always a valid ecmascript 3 program.”
Provided of course the program you started with was valid ecmascript 3, or close to valid ecmascript 3. The main point I wanted to make is that both “use strict” and jslint won’t cause the same problems that different script syntax can cause, which would require versioning.
breton (May 29, 2009 at 12:40 am)
Okay, I’ve had a look at some actual public statements by Dave McAllister, here http://blogs.adobe.com/open/2008/08/blog_entry_dated_81408_715_pm.html on the subject. Either RogerV has grossly misunderstood the situation, misread Dave McAllister, or he’s just blowing a lot of hot air just to get some reaction. I think there’s really a lot less drama in the situation than RogerV sees.
Mariusz Nowak (May 29, 2009 at 5:48 am)
What about Array generics? I assume that they won’t go into ECMAScript?
Scott (May 30, 2009 at 8:51 am)
@breton: Some programmers cannot accept that there would good technical reasons for the ES4 thing. I myself used to subscribe to RogerV’s theory. What changed my opinion was learning and falling in love with a couple of functional languages; and then realizing that js was actually pretty cool as it was (impossibly cool for how quickly it was put together by Eich). In other words, I found out that I was doing it wrong (thanks to people like Crockford and Resig for the that).
Also, and I know that I will ultimately lose this battle, but I actually like prototypal inheritance. It works nice with the idiom of adding methods at runtime, among other things. But the orthodoxy of classical inheritance will undoubtedly prevail, and programmers born into C++/Java will get to write code without learning anything new… (sigh)
Anyway, the drastic changes to the language were a bad idea, especially at a time when people were just starting to really get a handle on the language. Abandoning ES4 was the right call.
breton (June 1, 2009 at 11:34 pm)
I wouldn’t sweat too much about the “classical inheritence orthodoxy”, not everyone is going to be very interested in broadening their programming horizons. Sometimes it’s just a day job. A language as ubiquitous as javascript needs to be able to accomodate that nicely, or face a lot of bad will from people who would rather just use GWT and be done. I can’t say the mindset makes a lot of sense to me, Classical Inheritence languages have always seemed overly bulky, beaurocratic and verbose, too much so to seem fun. But it’s out there, and those people’s contributions can be valuable too; so far as it means making javascript more ubiquitous and less an obscure language like LISP, remaining only a secret weapon, and never on jobs requirements.
Scott (June 2, 2009 at 1:07 pm)
@breton: That’s funny… After I submitted my poorly-worded comment I thought about GWT. Some folks probably *should* use GWT, which is just fine at what it does. Like LISP, Javascript can be a “programmable programming language”.
Daniel Friesen (June 3, 2009 at 12:11 pm)
Interesting to see someone share some of my sentiments about
with() {}
.Even Crockford’s “Considered Harmful” article doesn’t really apply to ES5 strict-mode even if you don’t pull with out of it.
I personally love the ability to assign a number of classes to an object as a namespace, and then use
with() {}
to put those classes into scope for a block of code.It avoids the need to shove a pile of objects into the global scope all the time, and the need to either prefix piles of code with a namespace or assign a new variable for every single class you use.
It’s to bad we don’t have some sort of “use semi-strict mode”;
breton (June 3, 2009 at 11:58 pm)
With is problematic. I’ve heard that there’s considerable performance problems that are preventing ecmascript interpretations from moving forward. Presumably a script with “use strict” would be able to use some kind of faster interpretation method. I don’t really know anything about that.
The bigger problem with the with construct is this:
var myscope={firstname:”jane”, lastname:”doe”}
with(myscope){
firstName=”john”;
lastname=”smith”;
}
now we’ve got a global variable named “firstName”, and our object stores somone named jane smith. All due to a little error with case. This is a serious hazard.
BonD (June 4, 2009 at 12:33 pm)
Hi there!
I’ve just wanted to tell you that the Autocomplete Case Study on your book’s page is not working (Pro JavaScript Techniques)
(http://jquery.com/demo/auto/)
Good luck!
Daniel Friesen (June 5, 2009 at 3:57 pm)
@breton
“An attempt to assign foo = “bar”; where ‘foo’ hasn’t been defined will fail. Previously it would assign the value to the foo property of the global object (e.g. window.foo), now it just throws an exception.”
In Strict Mode, if with was still allowed then:
var myscope = { firstName: “Jane” };
with(myscope) {
firstName = “John”;
lastName = “Smith”;
}
Would throw a syntax error because lastName was not defined, it would not assign a property to the global object.
That aside, this is a bad use of the feature. There are good uses for the feature. Possibility for misuse != Feature should never be used. Where did the old “Don’t throw the baby out with the bathwater” statement go when people were discussing this feature?
var myWidgetSystem = { Widget: …, TextWidget: …, SomeOtherWidget: … };
…
with(myWidgetSystem) {
var tw = new TextWidget(“…”);
…
if ( tw instanceof Widget ) {
…
}
}
breton (June 7, 2009 at 9:40 pm)
“Would throw a syntax error because lastName was not defined, it would not assign a property to the global object.” in your version it was defined, but I’ll just assume that was a typo for now. What if it is defined?
function (firstName) {
var myscope = {firstname:”Jane”};
with(myscope) {
firstName=John;
}
}
“There are good uses for the feature. Possibility for misuse != Feature should never be used. ”
It’s more than a possibility of misuse. I maintain that it is a hazardous feature that is causing problems for implementors. I would say that the benefits do not outweigh the downsides of this one. The hazard isn’t so much in what the feature does, it’s in the fact that it is very easily misunderstood and highly likely to be misused, and causes the interpreter to run much slower that makes it a hazard.
“var myWidgetSystem = { Widget: …, TextWidget: …, SomeOtherWidget: … };
…
with(myWidgetSystem) {
var tw = new TextWidget(“…”);
…
if ( tw instanceof Widget ) {
…
}”
It would help your point immensely if you’d outlined what exactly it is you’re trying to accomplish here and why with is the only way to do so? It looks like you just added a property named “tw” to myWidgetSystem, which is an instance of myWidgetSystem.TextWidget, and are testing it against another property of myWidgetSystem.
On the surface it looks like javascript, without “with”, is missing a convenient way to dynamically declare variables. This kind of feature strikes me as kind of dicey and full of security hazards though. Who knows what’s in the object, or what kind of weird substitutions are possible from an attacker’s point of view? The danger there is in the implicit way that with just dumps everything in the object into the scope. It is much better to do this work explicitly, even if it’s more verbose than with. At least it’s visible at a glance exactly what it is you’re getting.
in ecmascript 5:
var myWidgetSystem = { widget: …, textWidget: …, someOtherWidget: … };
(function (m) {
var textWidget = m.textWidget;
var widget = m.widget;
var tw = Object.create(textWidget);
if(hasWidgetMethods(tw)){
…
}
})(myWidgetSystem);
I think if you look at it and think about it for a while, the above sort of code has fewer opportunities to be disrupted by the environment changing around it, or being tampered with by an attacker. The reasons for this are a bit numerous and complicated, so I’ll leave it as an excercise for the reader.