ECMAScript 5:
The New Parts
Any change to a standard is an
act of violence.
Complete implementations of
ECMAScript, Fifth Edition, are
now beginning to appear in the
ECMAScript
•
1999 Third Edition
ES3
•
2009 Fifth Edition
ES5
– Default
– Strict
•
For the short term, work in the intersection
of ES3 and ES5/Strict.
•
For the long term, work with ES5/Strict.
Lots of Little Things
•
Make the standard conform better to
reality.
•
Make the browsers conform better to each
other.
•
Where the browsers disagreed, we took
license to correct the standard.
•
Interoperability will be improved.
•
If you program well, this should have little
impact on you.
Goals of ES5
•
Don't break the web.
•
Improve the language for the users of the
language.
•
Third party security (mashups).
•
Protect stupid people from themselves.
New Syntax
Trailing Commas
{
"trailing": "comma",
}
[
"trailing",
"comma",
]
Reserved Word Relaxation
•
No reserved word restrictions on property
names.
var a = {
return: true,
function: liberty,
class: 'classitis',
};
a.return = false;
a.function();
alert(a.class);
Getters and Setters
function make_temperature(temperature) { return { get celsius() { return temperature; }, set celsius(value) { temperature = value; }, get fahrenheit() { return temperature * 9 / 5 + 32; }, set fahrenheit(value) { temperature = (value - 32) * 5 / 9; } }; }Multiline string literals
var long_line_1 = "This is a \
long line"; // ok
var long_line_2 = "This is a \
long line"; // syntax error
Constants
•
Infinity
•
NaN
parseInt
Regexp Literals
/regexp/ now produces new regular
expression objects every time.
Replacing
Object
or
Array
does not change the behavior
of
{}
or
[]
.
Brand New Methods
Methods can be added without
breaking syntax.
JSON
JSON.parse(text, reviver)
JSON.stringify(value, replacer,
space)
json2.js
https://github.com/douglascrockford/JSON-js
Function.prototype.bind
if (!Function.prototype.hasOwnProperty('bind')) { Function.prototype.bind = function (object) {
var slice = Array.prototype.slice, func = this, args = slice.call(arguments, 1); return function () { return func.apply(object, args.concat( slice.call(arguments, 0))); }; }; }
String.prototype.trim
if (!String.prototype
.hasOwnProperty('trim')) {
String.prototype.trim =
(function (re) {
return function () {
return this.replace(re,
"$1");
};
}(/^\s*(\S*(\s+\S+)*)\s*$/));
}
Array.prototype.every
if (!Array.prototype.hasOwnProperty('every')) {
Array.prototype.every = function(fun, thisp) { var i, length = this.length;
for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i) && !fun.call(thisp, this[i], i, this)) { return false; } } return true; }; }
Array.prototype.filter
if (!Array.prototype.hasOwnProperty('filter')) { Array.prototype.filter = function(fun, thisp) {
var i, length = this.length, result = [], value; for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i)) { value = this[i];
if (fun.call(thisp, value, i, this)) { result.push(value); } } } return result; }; }
Array.prototype.forEach
if (!Array.prototype.hasOwnProperty('forEach')) { Array.prototype.forEach =
function (fun, thisp) { var i,
length = this.length;
for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i)) {
fun.call(thisp, this[i], i, this); }
} };
Array.prototype.indexOf
if (!Array.prototype.hasOwnProperty('indexOf')) {Array.prototype.indexOf =
function (searchElement, fromIndex) { var i = fromIndex || 0, length = this.length; while (i < length) { if (this.hasOwnProperty(i) && this[i] === searchElement) { return i; } i += 1; } return -1; }; }
Array.prototype.lastIndexOf
if (!Array.prototype.hasOwnProperty('lastIndexOf')) { Array.prototype.lastIndexOf =
function (searchElement, fromIndex) { var i = fromIndex; if (typeof i !== 'number') { i = this.length - 1; } while (i >= 0) { if (this.hasOwnProperty(i) && this[i] === searchElement) { return i; } i -= 1; } return -1; }; }
Array.prototype.map
if (!Array.prototype.hasOwnProperty('map')) {
Array.prototype.map = function(fun, thisp) { var i, length = this.length, result = []; for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i)) { result[i] = fun.call(thisp, this[i], i, this); } } return result; }; }
Array.prototype.reduce
if (!Array.prototype.hasOwnProperty('reduce')) {Array.prototype.reduce =
function (fun, initialValue) { var i,
length = this.length;
for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i)) {
initialValue = fun.call(undefined, initialValue, this[i], i, this); }
}
return initialValue; };
Array.prototype.reduceRight
if (!Array.prototype.hasOwnProperty('reduceRight')) { Array.prototype.reduceRight =
function (fun, initialValue) { var i = this.length - 1;
while (i >= 0) {
if (this.hasOwnProperty(i)) {
initialValue = fun.call(undefined, initialValue, this[i], I, this); } i -= 1; } return initialValue; }; }
Array.prototype.some
if (!Array.prototype.hasOwnProperty('some')) {
Array.prototype.some = function(fun, thisp) { var i, length = this.length;
for (i = 0; i < length; i += 1) { if (this.hasOwnProperty(i) && fun.call(thisp, this[i], i, this)) { return true; } } return false; }; }
Date.now()
if (!Date.hasOwnProperty('now')) {
Date.now = function () {
return (new Date()).getTime();
};
Date.prototype.toISOString
if (!Date.prototype.hasOwnProperty('toISOString')) { Date.prototype.toISOString = function () { function f(n) { return n < 10 ? '0' + n : n; } return this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z'; }; }Date
new Date(
string
)
and
Date.parse(
string
)
Array.isArray
if (!Array.hasOwnProperty('isArray')) {
Array.isArray = function (value) {
return Object.prototype
.toString.apply(value) ===
'[object Array]';
};
}
Object.keys
if (!Object.hasOwnProperty('keys')) {
Object.keys = function (object) {
var name, result = [];
for (name in object) {
if (Object.prototype
.hasOwnProperty
.call(object, name)) {
result.push(name);
}
}
return result;
};
}
Object.create
if (!Object.hasOwnProperty('create')) { Object.create = function (object,
properties) { var result; function F() {} F.prototype = object; result = new F(); if (properties !== undefined) { Object.defineOwnProperties(object, properties); } return result; }; }
Meta Object API
Control over the attributes of the
properties of the objects.
Two kinds of properties:
Data properties
Attributes
•
A property is a named collection of
attributes.
•
value:
any JavaScript value
•
writeable:
boolean
•
enumerable: boolean
•
configurable: boolean
•
get:
function () {… return value;}
Data Property
var my_object = {foo: bar};
var my_object =
Object.create(Object.prototype);
Object.defineProperty(my_object,
'foo', {
value: bar,
writeable: true,
enumerable: true,
configurable: true
});
Accessor property
Object.defineProperty(my_object, 'inch', {
get: function () {
return this.mm / 25.4;
},
set: function (value) {
this.mm = value * 25.4;
},
enumerable: true
});
Meta Object API
Object.defineProperty(
object
,
key
,
descriptor
)
Object.defineProperties(
object
,
object_of_descriptors
)
Object.getOwnPropertyDescriptor(
Object.getOwnPropertyNames(
object
)
Object.getPrototypeOf(
object
)
Best not to use these.
Secure frameworks may ban their
use.
function replace_prototype(object, prototype) { var result = Object.create(prototype);
Object .getOwnPropertyNames(object) .forEach(function (key) { Object.defineProperty(result, key, Object.getOwnPropertyDescriptor( object, key)); }); return result; }
Object Extensibility
Object.preventExtentions(
object
)
Object.seal(
object
)
Object.freeze(
object
)
Object.isExtensible(
object
)
Object.isSealed(
object
)
Object.isFrozen(
object
)
Unintended Inheritance
var word_count = {};
text.split(/[\s.,?!":;]+/)
.forEach(function count_word(word) {
if (word_count[word]) {
word_count[word] += 1;
} else {
word_count[word] = 1;
}
});
•
Accidental collisions: Fails when
word ===
'constructor'
Solutions in ES5
•
Object.create(null)
creates an
object that does not inherit anything.
•
Set the
enumerable
attribute to
false
when adding methods to prototypes. That
keeps them out of
for in
enumerations.
•
Object.keys(
object
)
produces an array
of strings, the enumerable keys of the own
(not inherited) properties.
Strict Mode
The most important new feature in
ECMAScript, Fifth Edition.
Strict Mode
•
Backward compatible pragma.
'use strict';
•
File form. First statement in a file. (avoid)
•
Function form. First statement in a
function.
New Reserved Words
•
implements
•
interface
•
let
•
package
•
private
•
protected
•
public
•
static
•
yield
Strict Mode
•
No more implied global variables within functions.
•
this
is not bound to the global object by function form.
•
apply
and
call
do not default to the global object.
•
No
with
statement.
•
Setting a writeable: false property will throw.
•
Deleting a configurable: false property will throw.
•
Restrictions on
eval
.
•
eval
and
arguments
are reserved.
•
arguments
not linked to parameters.
•
No more
arguments.caller
or
arguments.callee
.
•
No more octal literals.
•
Duplicate names in an object literal or function parameters
are a syntax error.
Forgetting to use the
new
prefix will now throw an
exception, not silently clobber
the global object.
Strict Mode
addEventListener(…); //error
Strict Mode
•
There are no methods for determining if strict mode is
on, but it is easy to make your own.
function in_strict_mode() { return (function () { return !this; }()); } function strict_mode_implemented() { return (function () { 'use strict'; return !this; }()); }