Welcome our
new ES5 Overlords

Hello

A good time to talk about ES5

ES5

There is magic in ES5

Some JS

A list of German bands

Clicking the button should show the band name


var bands = ['Apparat', 'Boy', 'Kraftklub'];
for (var i = 0; i < bands.length; i++) {
  var band = bands[i],
    button = document.createElement('button');
  button.appendChild(document.createTextNode(band));
  button.addEventListener('click', function(){
    alert(band);
  });
  document.body.appendChild(button);
}

This code has two problems

This means we can only see KraftKlub

Some basic JS (fixed)


var bands = ['Apparat', 'Boy', 'Kraftklub'];
for (var i = 0; i < bands.length; i++) {
  var band = bands[i],
    button = document.createElement('button');
  button.appendChild(document.createTextNode(band));
  (function(band){
    button.addEventListener('click', function(){
      alert(band);
    });
  })(band);
  document.body.appendChild(button);
}

Same thing in ES5

['Apparat', 'Boy', 'Kraftklub'].forEach(function(band){
  var button = document.createElement('button');
  button.appendChild(document.createTextNode(band));
  button.addEventListener('click', function(){
    alert(band);
  });
  document.body.appendChild(button);
})

Let's do it for more things!

Safe Extension of Inbuilt Methods

No, really

Quick History* Lesson

*History may be more recent than expected

ES3: Non-native methods appear during iteration

Object.prototype.oldStyleMethod = function oldStyleMethod (){};
var someObject = {};
for (var key in someObject) { console.log(key) };

ES3: But native methods don't

This is why toString() doesn't appear in 'for' loops.

console.log(Object.prototype.toString);
function toString() { [native code] };

Added methods are always enumerable in ES3

ES5: Non enumerable methods can be added

Requires native ES5 (not shimmable)

Object.defineProperty( Object.prototype, "newStyleMethod", {
  value: function newStyleMethod(){},
  enumerable: false
});
for (var key in someObject) { console.log(key) };

That's not the only problem

Generic names

Past conflicts:

Prefixing

Set a sensible prefix

UnderscoreSugar
MethodsNoYes
Regular 'for' loopsYesNo
Conflict-freeYesNo
UnderscoreAgave (ES5 only)Sugar
MethodsNoYesYes
Regular 'for' loopsYesYesNo
Conflict-freeYesYesNo

Using ES5 defineProperty() and prefixing, Agave.JS has had no conflicts since it was created (early 2012).

Other reasons:

More magic: Live Binding

An experiment in two parts

  1. A data → DOM binding (I like mustache, so I use Ractive).
  2. Data changes applied to binding live via object.defineProperty()

Live binding with defineProperty

var livebind = function(object, binding, properties){
  properties.forEach(function(property){
    var hiddenProperty = '_'+property
    Object.defineProperty(object, property, {
      get: function(){ return testData[hiddenProperty]; },
      set: function(newValue){
        testData[hiddenProperty] = newValue;
        binding.set(property, newValue)
      },
      enumerable: true,
      configurable: true
    });
  })
}

Note

  1. This is an experiment
  2. We also use prototype chain injection (see links) for array.length magic

ES5-only is coming

Thanks.

@mikemaccana

Enjoy the week