ecmascript 5
DESCRIPTION
The new ECMAScript 5 standard brings on the table some very nice features you can use right away in the modern browsers. The presentation is a big overview of them.TRANSCRIPT
ECMAScript 5
Damian Wielgosikvarjs.com
front-trends.com@varjs
Hey, what is that ECMAScript actually?
let’s create a simplest object ever
var obj = {};
let’s add a property to it
var obj = { foo : 1};
let’s read that property
var obj = { foo : 1};
obj.foo; // 1 - this is how we read a value from property "foo" of the object "obj"
let’s modify that property
var obj = { foo : 1};
obj.foo = 2;obj.foo; // 2
every object except null takes some stuff from
Object.prototype
var obj = {};typeof obj.hasOwnProperty; // "function"
var obj = {};obj.hasOwnProperty === Object.prototype.hasOwnProperty; // true
hasOwnProperty is a good example of Object.prototype
property
is there a way to create an object without
Object.prototype properties?
Object.create
var obj = Object.create(null); // ECMA 5 way
var obj = Object.create(null); // ECMA 5 waytypeof obj.hasOwnProperty; // "undefined"
Object.create(null) does not use Object.prototype
Object.create(null) - pure object
Object.create(null) you don’t get:
•.constructor•.toString•.toLocaleString•.valueOf•.hasOwnProperty•.isPrototypeOf•.propertyIsEnumerable
Object.create(null) - imagine null-like object with
allowed extensions
Dude, I want Object.prototype
Object.create - put a prototype you want to
inherit from as a first argument
var obj = Object.create({});typeof obj.hasOwnProperty; // "function"obj instanceof Object; // true
Hell yeah!
var obj = Object.create({});obj.__proto__.__proto__ === Object.prototype; // true (ES3 way)
btw. there is Object.isPrototypeOf
var obj = Object.create({});Object.prototype.isPrototypeOf(obj); // true
var obj = Object.create({});obj.__proto__.__proto__ === Object.prototype; // true (ES3 way)
same as
everything starts with Object.prototype, I’m sure you
lied!
var obj = Object.create(null);Object.prototype.isPrototypeOf(obj); // false
isPrototypeOf is even from ECMA 3!
Object.getPrototypeOf is a new stuff however...
var obj = Object.create({});Object.getPrototypeOf(obj) === obj.__proto__; // true
with Object.getPrototypeOf you simply forget about
non-standard obj.__proto__
var fn = function() {};fn.prototype.foobar = 1;
var obj = new fn();Object.getPrototypeOf(obj) === fn.prototype;
var obj = Object.create({});Object.prototype.isPrototypeOf(obj); // true
var obj = Object.create({});Object.getPrototypeOf(Object.getPrototypeOf(obj)) === Object.prototype; // true// no __proto__!
same as
Ok, you won. Tell me more about Object.create!
if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error('Object.create implementation only accepts the first parameter.'); } function F() {}; F.prototype = o; return new F(); }; }
wow, we found a polyfill!
inheritance?
var animal = Object.create({ age : null, setAge: function(age) { this.age = age; }});
var bird = Object.create(animal);bird.setAge(10);bird.age; // 10
give me analogy, I still remember ECMA3
var Animal = function() {};Animal.prototype = { age : null, setAge: function(age) { this.age = age; }};
var Bird = function() {};Bird.prototype = new Animal();
var bird = new Bird();bird.setAge(10);bird.age; // 10
more analogies?
var Animal = function() {}; var obj = new Animal();
var obj2 = Object.create(Animal.prototype);
obj2.constructor === obj.constructor; // true
not enough, you know that
var obj = {};// does the same job asvar obj2 = Object.create(Object.prototype);
more ECMA5!
Object.defineProperty
how we used to add new properties
var obj = {};obj.myProperty = 100;
how we do it with defineProperty
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, // default: undefined writable : true, // default: false enumerable : true, // default: false configurable : true // default: false});
obj.foobar; // 100
writable?!
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, writable : false});
obj.foobar; // 100obj.foobar = 200;obj.foobar; // 100
writable: falseforget about changing
property’s value
enumerable?!
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, enumerable : false});
for (var i in obj) { console.log(obj[i]);}// nothing happened
however...
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, enumerable : true !});
for (var i in obj) { console.log(obj[i]);}// „foobar” !
configurable?!
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, configurable : false});
delete obj.foobar; // falseobj.foobar; // 100
var obj = {};Object.defineProperty(obj, "foobar", { value : 100, configurable : false}); // it’s ok, we just defined a foobar property not to be configurable
Object.defineProperty(obj, "foobar", { configurable : true}); // throws a TypeError
Object.defineProperty(obj, "foobar", { writable : true}); // throws a TypeError
Object.defineProperty(obj, "foobar", { enumerable : true}); // throws a TypeError
Summary of descriptors
var obj = {}; obj.foobar = 100;
Object.defineProperty(obj, "foobar", { value : 100, writable : true, configurable : true, enumerable : true});
same as
Object.defineProperty(obj, "foobar", { value : 100});
Object.defineProperty(obj, "foobar", { value : 100, writable : false, configurable : false, enumerable : false});
same as
Summary of descriptors
IE8 allows you use it only with DOM objects
Oh, there are setters and getters
setters
var rect = { x: 5, y: 2};
Object.defineProperty(rect, "area", { set: function(value) { throw new Error("Cannot set a value"); }, get: function() { return this.x * this.y; }});
rect.area = -21; // Error: Cannot set a value
watch out
var rect = { x: 5, y: 2};
Object.defineProperty(rect, "area", { set: function(value) { throw new Error("Cannot set a value"); }, get: function() { return this.x * this.y; }, writable: false // TypeError: Invalid property. A property cannot both have accessors and be writable or have a value: #<Object>});
getters
var rect = { x: 5, y: 2};
Object.defineProperty(rect, "area", { set: function(value) { throw new Error("Cannot set a value"); }, get: function() { return this.x * this.y; }});
rect.area; // 10 (5 * 2 = 10)
Object.defineProperties
var obj = {};
Object.defineProperties(obj, { "firstname": { value: "Damian", writable: false }, "nickname": { value: "varjs", writable: false }});
obj.firstname; // "Damian"obj.nickname; // "varjs"
Object.defineProperties in other words
Object.defineProperties = function(obj, props) { for (var prop in props) { Object.defineProperty(obj, prop, props[prop]); }};
back to Object.create...
var obj = Object.create({}, { "foobar" : { value: 100, writable: true, enumerable: false }});
obj.foobar; // 100
Object.getOwnPropertyDescriptor
var obj = {};
Object.defineProperties(obj, { "firstname": { value: "Damian", writable: true }, "nickname": { value: "varjs", writable: true }});
obj.firstname; // "Damian"obj.nickname; // "varjs"
Object.getOwnPropertyDescriptor(obj, "firstname"); // Object { value="Damian", writable=true, enumerable=false, configurable=false}
Object.getOwnPropertyNames
works for arrays!
var arr = ["a", "b", "c"]; Object.getOwnPropertyNames(arr); // ["length", "0", "1", "2"]
works for objects!
var obj = { foo: "bar", barbar: "barbar"};
Object.getOwnPropertyNames(obj); // ["foo", "barbar"]
works even with not enumerable properties
var obj = {};Object.defineProperty(obj, "foobar", { enumerable: false});
Object.getOwnPropertyNames(obj); // ["foobar"]
Object.keys
var obj = { foo: 1, bar: 2, foobar: 3};
Object.keys(obj); // ["foo", "bar", "foobar"]
it returns only enumerables...
var obj = Object.create({}, { "foo" : { value: 100, enumerable: false ! }, "bar" : { value: 200, enumerable: true }});
Object.keys(obj); // ["bar"] !
no „foo” since it’s not enumerable
arrays?
var arr = [1, 2, 3];Object.keys(arr); // ["0", "1", "2"]
Polyfill?
if(!Object.keys) { Object.keys = function(o) { if (o !== Object(o)) { throw new TypeError('Object.keys called on non-object'); } var ret = []; var p; for (p in o) { if (Object.prototype.hasOwnProperty.call(o, p)) { ret.push(p); } } return ret; };}
Object.seal
var obj = { foo: 1};
Object.seal(obj);obj.myEvilProperty = 1337;obj.myEvilProperty; // undefined
It prevents new properties from being added to the sealed
object!
var obj = { foo: 1};
Object.seal(obj);Object.defineProperty(obj, "foo", { value: "boom" }); // throws a TypeError
Object.seal makes all the properties not configurable
var obj = { foo: 1};
Object.seal(obj);Object.defineProperty(obj, "foo", { get: function() { return "g"; } }); // throws a TypeError
var obj = { foo: 1};
Object.seal(obj);delete obj.foo; // does nothingobj.foo; // 1
Object.isSealed
var obj = { foo: 1};
Object.seal(obj);Object.isSealed(obj); // true
Object.freeze
well, you can do nothing
Freezes an object: that is, prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed. In essence the object is made effectively immutable. The method returns the object being frozen.
- MDN - the best source of knowledge
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/freeze
var obj = { foo: 1};
Object.freeze(obj);obj.myEvilProperty = 1337;obj.myEvilProperty; // undefined
var obj = { foo: 1};
Object.freeze(obj);obj.foo = 1337;obj.foo; // 1
var obj = { foo: 1};
Object.freeze(obj);Object.defineProperty(obj, "foo", { value: "boom" }); // throws a TypeError
var obj = { foo: 1};
Object.freeze(obj);delete obj.foo; // false
Object.isFrozen
var obj = { foo: 1};
Object.freeze(obj);Object.isFrozen(obj); // true
Object.preventExtensions
Simply, you can’t add new properties
var obj = { foo: 1};
Object.preventExtensions(obj);obj.myEvilProperty = 1337;obj.myEvilProperty; // undefined
How it’s different than Object.seal?
You can remove properties!
var obj = { foo: 1};
Object.seal(obj);delete obj.foo; // false
var obj2 = { bar: 2};
Object.preventExtensions(obj2);delete obj2.bar; // true
You can change descriptors!
var obj = { foo: 1};
Object.seal(obj);Object.defineProperty(obj, "foo", { enumerable: false}); // throws a TypeError
var obj2 = { bar: 2};
Object.preventExtensions(obj2);Object.defineProperty(obj2, "bar", { enumerable: false}); // it's ok
Object.isExtensible
var obj = { foo: 1};
Object.preventExtensions(obj);Object.isExtensible(obj); // false
More ECMAScript 5?
Array.prototype.reduceRightArray.prototype.reduceArray.prototype.filterArray.prototype.map
Array.prototype.forEachArray.prototype.someArray.prototype.every
Array.prototype.lastIndexOfArray.prototype.indexOf
More?!
Function.prototype.bind
Function.prototype.bind = function(){ var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift(); return function(){ return fn.apply(object, args.concat(Array.prototype.slice.call(arguments))); }; };
Date.now()
Date.now() === +new Date()
Date.now(); // 1318362644511
Array.isArray
We used to use...
Object.prototype.toString.call([]) === "[object Array]";
Now we use...
Array.isArray(null); // falseArray.isArray([]); // trueArray.isArray({ length: 1 }); // false
String.prototype.trim
We used to use...
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, "");}
"my string ".trim(); // "my string"
Now we use...
"my string ".trim(); // "my string"
In ECMAScript 5 we have...
Native JSON!
typeof JSON === "object"; // true
var foo = {}; foo.bar = "new property"; foo.baz = 3; var JSONfoo = JSON.stringify(foo); // {"bar":"new property","baz":3}var foo = JSON.parse(JSONfoo); // yet again we have an object
strict mode
"use strict";eval = 17;arguments++;++eval;var obj = { set p(arguments) { } };var eval;try { } catch (arguments) { }function x(eval) { }function arguments() { }var y = function eval() { };var f = new Function("arguments", "'use strict'; return 17;");
all of these throw errors
"use strict";var fn = function() { return arguments.callee; }; fn();
more: https://developer.mozilla.org/en/JavaScript/Strict_mode