ECMA5 approach to writing JavaScript
frameworks
Anzor Bashkhaz
@anzor_b
Isaac Gordezky
@igordezky
ECMA5
What is ECMA5?
• ECMAScript = language of JavaScript
• Final draft for v5 presented in April 2009
• Object creation/manipulation
• Supported in all major platforms
http://kangax.github.io/es5-compat-table/
API design
What is an API?
• API exposes ways to use a library/framework
• Ex: underscore
• Users of API can’t see implementation
• aka. Public API
API: Real world example
Dissecting the JavaScript Object:
Type and Prototype
5
Type
What is a type?
• Instance factory
• JavaScript ‘Object’ is a type
• Made up of:
• Constructor (returns new instance)
• Static methods (create, call,…)
• Prototype
Type
What is a type?
• Instance factory
• JavaScript ‘Object’ is a type
• Made up of:
• Constructor (returns new instance)
• Static methods (create, call,…)
• Prototype
Prototype
What is a prototype?
• Prototype = definition for new instances
• = Public API
• Object.prototype
Prototype
What is a prototype?
• Prototype = definition for new instances
• = Public API
• Object.prototype
Inside an instance
Ex: Dissecting the instance of Object
var foo = {
hello : function(){
return “hello world”;
}
};
console.log(foo);
Inside an instance
Ex: Dissecting the instance of Object
var foo = {
hello : function(){
return “hello world”;
}
};
console.log(foo);
Inside an instance
Ex: Dissecting the instance of Object
var foo = {
hello : function(){
return “hello world”;
}
};
console.log(foo);
What is __proto__?
__proto__
“Special” property on every JavaScript Object.
• foo was created from Object.
var foo = {}
• __proto__ of foo points at prototype of Object.
• Object.create(definition)
• Returns object (instance) with __proto__ pointing at
definition
• Returned object can be Object.create’d again and again
__proto__
Ex: Prototype chain and simple inheritance
var foo = {};
var bar = Object.create(foo);
__proto__
Ex: Prototype chain and simple inheritance
var foo = {};
var bar = Object.create(foo);
bar inherits methods from foo, while foo inherits methods from Object.
16
Demo
Custom Types
Ex: create type with name “type<Shape>”
var Shape = {};
Shape.constructor = { name: “type<Shape>" };
• Makes it easier to read in console versus “Object”
Custom Types
Ex: Add a prototype so instance are called “Shape”
• Add a prototype property
Shape.prototype = {};
• Set prototype.constructor.name to “Shape”
Shape.prototype.constructor = { name: “Shape” };
Custom Types – constructor
Ex: Add a constructor that returns instance of Shape
• Object.create() creates a new unique instance of Shape
Shape.create = function(){
return Object.create(Shape.prototype);
};
var shape1 = Shape.create();
var shape2 = Shape.create();
shape1.color = “blue”;
Custom Types – constructor
Ex: Add a constructor that returns instance of Shape
• Object.create() creates a new unique instance of Shape
Shape.create = function(){
return Object.create(Shape.prototype);
};
var shape1 = Shape.create();
var shape2 = Shape.create();
shape1.color = “blue”;
Properties
21
Defining Properties
• Good API design = preventing unintended use
• Read-only properties
Object.defineProperty(object, propertyName, descriptor)
• Descriptor
• Enumerable
• Configurable
• Writable
• Value
Read more at MDN (http://mzl.la/1cCtwPN)
Defining Properties
• Enumerable
true if the property is present while iterating through the object. (for prop in obj).
Defaults to false.
• Configurable
true if the property descriptor can be modified or property deleted on object.
Defaults to false.
• Writable
true if the property’s value can be changed? ( radius= 20)
Defaults to false.
• Value
Value of the property
Defining Properties
var Shape = {};
Object.defineProperty(Shape, “constructor”,
{
value: { name: “type<Shape>” }
});
Object.defineProperty(Shape, “prototype”,
{
value: {}
});
Object.defineProperty(Shape.prototype, “constructor”,
{
value: { name: “Shape” }
});
Defining Properties
Original (assignment)
ECMA5
(Object.defineProperty)
Read-only properties guard the API from unintended use.
Public vs. Private
26
Private
Ex: Add a private area to instances of Shape
Shape.create = function() {
var privateArea = {
public : Object.create(Shape.prototype),
secret : 5,
}
return privateArea.public;
};
var shape1 = Shape.create();
shape1.color = “blue”;
Private
Ex: Add methods to inspect the private area
Shape.create = function() {
var privateArea = {
public : Object.create(Shape.prototype),
secret : Math.floor((Math.random() * 10) + 1), //random secret per instance
privateInspect : function() {
console.log(this); //this points at instance
}
};
//public inspect function
privateArea.public.inspect = function() {
return privateArea.privateInspect();
};
return privateArea.public;
};
Private
Result:
Getters and Setters
30
Getters and Setters
• Important concept in framework design (especially UI)
• Backbone.js uses “set()” method
Ex: model.set(propertyName, value);
> “change” event triggered
> Views update their UI
• Ideally we want:
shape1.color = “blue”;
> This should trigger a color change (using DOM/canvas)
• Possible with Object.defineProperty
ECMA5 way to define setters/getters
Getters and Setters
Ex: Define setter for color to notify of change
var circle = {},
var currentValue;
Object.defineProperty(circle, “color”,
{
get: function(){
return currentValue;
},
set : function(value){
currentValue = value;
console.log(“color changed to “ + value);
}
});
Getters and Setters
Ex: Define setter for color to notify of change
var circle = {},
var currentValue;
Object.defineProperty(circle, “color”,
{
get: function(){
return currentValue;
},
set : function(value){
currentValue = value;
console.log(“color changed to “ + value);
}
});
Getters and Setters
Ex: Helper function for defining properties
var defineProperty = function(object, propertyName) {
Object.defineProperty(object, propertyName, {
get : function() {
return object[propertyName];
},
set : function(value) {
object[propertyName] = value;
console.log(propertyName + "changed to " + value);
}
});
};
var circle2 = {};
defineProperty(circle2, "color");
Beyond Private
Covered so far:
Public
• Leverages inheritance pattern
• Final instance has access to all methods in __proto__ chain
Private
• Instance specific data unexposed to the outside
What about inheriting non-public methods?
Protected to the rescue!
Protected
• Leverages inheritance pattern
• Allows child types to re-implement methods from their parents.
• Provides non-public APIs to child types.
The extend! Requirejs plugin
36
extend!
• Declarative syntax for public, private and protected
functions
• hooks for init and destroy
• Public values are defined as:
• Property getters/setters on public
• Property stored in privateArea
• Non-functions in public create notifiable properties
Ex: size triggers sizeChanged()
• All methods have ‘this’ pointing to the privateArea
• Uses require.js’ plugin system to hide parser
Case Study: A Simple Class System
38
Shapes
Objective: Build an API to draw shapes using HTML5 canvas.
type<Shape>
• Manage canvas and DOM
• Properties: color
• Protected interface: resize
• Abstract interface: draw
type<Circle> extends type<Shape>
• Implements draw interface
• Properties: radius
• Leverages resize interface
Shape.color: a property
Shape.color (Public)
• Property available on any shape object
Shape.colorChanged (Private)
• Automatically triggered when the color
property is changed
• Triggers a re-draw
Shape.color (Private)
• Stores the value of color in Shape’s privateArea
• Allows Shape’s methods to access color
without the setter/getter
Shape.resize: a protected interface
Size
• Public read-only property of Shape
• Stored in the privateArea of Shape
Resize
• Exposed to child types through protected
• Sets size in the privateArea of Shape
• Resizes DOM elements
Radius
• Public property of Circle
• Triggers protected Shape.resize
Shape.draw: a virtual method
Shape.draw (Public)
• Public draw API for all Shapes
• Calls virtual draw with canvas context
from Shape’s privateArea
Shape.draw (Protected)
• Abstract protected draw function
must be overridden by child classes
Circle.draw (Protected)
• Overrides Shape.draw (Protected)
• Doesn’t know or care where context
came from
Demo
43
Thank you
Anzor Bashkhaz
@anzor_b
Isaac Gordezky
@igordezky

ECMA5 approach to building JavaScript frameworks with Anzor Bashkhaz

  • 1.
    ECMA5 approach towriting JavaScript frameworks Anzor Bashkhaz @anzor_b Isaac Gordezky @igordezky
  • 2.
    ECMA5 What is ECMA5? •ECMAScript = language of JavaScript • Final draft for v5 presented in April 2009 • Object creation/manipulation • Supported in all major platforms http://kangax.github.io/es5-compat-table/
  • 3.
    API design What isan API? • API exposes ways to use a library/framework • Ex: underscore • Users of API can’t see implementation • aka. Public API
  • 4.
  • 5.
    Dissecting the JavaScriptObject: Type and Prototype 5
  • 6.
    Type What is atype? • Instance factory • JavaScript ‘Object’ is a type • Made up of: • Constructor (returns new instance) • Static methods (create, call,…) • Prototype
  • 7.
    Type What is atype? • Instance factory • JavaScript ‘Object’ is a type • Made up of: • Constructor (returns new instance) • Static methods (create, call,…) • Prototype
  • 8.
    Prototype What is aprototype? • Prototype = definition for new instances • = Public API • Object.prototype
  • 9.
    Prototype What is aprototype? • Prototype = definition for new instances • = Public API • Object.prototype
  • 10.
    Inside an instance Ex:Dissecting the instance of Object var foo = { hello : function(){ return “hello world”; } }; console.log(foo);
  • 11.
    Inside an instance Ex:Dissecting the instance of Object var foo = { hello : function(){ return “hello world”; } }; console.log(foo);
  • 12.
    Inside an instance Ex:Dissecting the instance of Object var foo = { hello : function(){ return “hello world”; } }; console.log(foo); What is __proto__?
  • 13.
    __proto__ “Special” property onevery JavaScript Object. • foo was created from Object. var foo = {} • __proto__ of foo points at prototype of Object. • Object.create(definition) • Returns object (instance) with __proto__ pointing at definition • Returned object can be Object.create’d again and again
  • 14.
    __proto__ Ex: Prototype chainand simple inheritance var foo = {}; var bar = Object.create(foo);
  • 15.
    __proto__ Ex: Prototype chainand simple inheritance var foo = {}; var bar = Object.create(foo); bar inherits methods from foo, while foo inherits methods from Object.
  • 16.
  • 17.
    Custom Types Ex: createtype with name “type<Shape>” var Shape = {}; Shape.constructor = { name: “type<Shape>" }; • Makes it easier to read in console versus “Object”
  • 18.
    Custom Types Ex: Adda prototype so instance are called “Shape” • Add a prototype property Shape.prototype = {}; • Set prototype.constructor.name to “Shape” Shape.prototype.constructor = { name: “Shape” };
  • 19.
    Custom Types –constructor Ex: Add a constructor that returns instance of Shape • Object.create() creates a new unique instance of Shape Shape.create = function(){ return Object.create(Shape.prototype); }; var shape1 = Shape.create(); var shape2 = Shape.create(); shape1.color = “blue”;
  • 20.
    Custom Types –constructor Ex: Add a constructor that returns instance of Shape • Object.create() creates a new unique instance of Shape Shape.create = function(){ return Object.create(Shape.prototype); }; var shape1 = Shape.create(); var shape2 = Shape.create(); shape1.color = “blue”;
  • 21.
  • 22.
    Defining Properties • GoodAPI design = preventing unintended use • Read-only properties Object.defineProperty(object, propertyName, descriptor) • Descriptor • Enumerable • Configurable • Writable • Value Read more at MDN (http://mzl.la/1cCtwPN)
  • 23.
    Defining Properties • Enumerable trueif the property is present while iterating through the object. (for prop in obj). Defaults to false. • Configurable true if the property descriptor can be modified or property deleted on object. Defaults to false. • Writable true if the property’s value can be changed? ( radius= 20) Defaults to false. • Value Value of the property
  • 24.
    Defining Properties var Shape= {}; Object.defineProperty(Shape, “constructor”, { value: { name: “type<Shape>” } }); Object.defineProperty(Shape, “prototype”, { value: {} }); Object.defineProperty(Shape.prototype, “constructor”, { value: { name: “Shape” } });
  • 25.
  • 26.
  • 27.
    Private Ex: Add aprivate area to instances of Shape Shape.create = function() { var privateArea = { public : Object.create(Shape.prototype), secret : 5, } return privateArea.public; }; var shape1 = Shape.create(); shape1.color = “blue”;
  • 28.
    Private Ex: Add methodsto inspect the private area Shape.create = function() { var privateArea = { public : Object.create(Shape.prototype), secret : Math.floor((Math.random() * 10) + 1), //random secret per instance privateInspect : function() { console.log(this); //this points at instance } }; //public inspect function privateArea.public.inspect = function() { return privateArea.privateInspect(); }; return privateArea.public; };
  • 29.
  • 30.
  • 31.
    Getters and Setters •Important concept in framework design (especially UI) • Backbone.js uses “set()” method Ex: model.set(propertyName, value); > “change” event triggered > Views update their UI • Ideally we want: shape1.color = “blue”; > This should trigger a color change (using DOM/canvas) • Possible with Object.defineProperty ECMA5 way to define setters/getters
  • 32.
    Getters and Setters Ex:Define setter for color to notify of change var circle = {}, var currentValue; Object.defineProperty(circle, “color”, { get: function(){ return currentValue; }, set : function(value){ currentValue = value; console.log(“color changed to “ + value); } });
  • 33.
    Getters and Setters Ex:Define setter for color to notify of change var circle = {}, var currentValue; Object.defineProperty(circle, “color”, { get: function(){ return currentValue; }, set : function(value){ currentValue = value; console.log(“color changed to “ + value); } });
  • 34.
    Getters and Setters Ex:Helper function for defining properties var defineProperty = function(object, propertyName) { Object.defineProperty(object, propertyName, { get : function() { return object[propertyName]; }, set : function(value) { object[propertyName] = value; console.log(propertyName + "changed to " + value); } }); }; var circle2 = {}; defineProperty(circle2, "color");
  • 35.
    Beyond Private Covered sofar: Public • Leverages inheritance pattern • Final instance has access to all methods in __proto__ chain Private • Instance specific data unexposed to the outside What about inheriting non-public methods? Protected to the rescue! Protected • Leverages inheritance pattern • Allows child types to re-implement methods from their parents. • Provides non-public APIs to child types.
  • 36.
  • 37.
    extend! • Declarative syntaxfor public, private and protected functions • hooks for init and destroy • Public values are defined as: • Property getters/setters on public • Property stored in privateArea • Non-functions in public create notifiable properties Ex: size triggers sizeChanged() • All methods have ‘this’ pointing to the privateArea • Uses require.js’ plugin system to hide parser
  • 38.
    Case Study: ASimple Class System 38
  • 39.
    Shapes Objective: Build anAPI to draw shapes using HTML5 canvas. type<Shape> • Manage canvas and DOM • Properties: color • Protected interface: resize • Abstract interface: draw type<Circle> extends type<Shape> • Implements draw interface • Properties: radius • Leverages resize interface
  • 40.
    Shape.color: a property Shape.color(Public) • Property available on any shape object Shape.colorChanged (Private) • Automatically triggered when the color property is changed • Triggers a re-draw Shape.color (Private) • Stores the value of color in Shape’s privateArea • Allows Shape’s methods to access color without the setter/getter
  • 41.
    Shape.resize: a protectedinterface Size • Public read-only property of Shape • Stored in the privateArea of Shape Resize • Exposed to child types through protected • Sets size in the privateArea of Shape • Resizes DOM elements Radius • Public property of Circle • Triggers protected Shape.resize
  • 42.
    Shape.draw: a virtualmethod Shape.draw (Public) • Public draw API for all Shapes • Calls virtual draw with canvas context from Shape’s privateArea Shape.draw (Protected) • Abstract protected draw function must be overridden by child classes Circle.draw (Protected) • Overrides Shape.draw (Protected) • Doesn’t know or care where context came from
  • 43.
  • 44.

Editor's Notes

  • #20 Since the purpose of a type is to create an instance out of the protoype, our Shape type needs a create function, that returns a new instance of a shape.(We need to Object.create the prototype, otherwise every instance of shape will point at the same prototype instead of being separate instances.)Next, we’ll create two instances of Shape and assign a blue color to one.[var shape1 = Shape.create();var shape2 = Shape.create();shape1.color = “blue”;&gt;shape1&gt;shape2](Both shapes have a color property of blue, and this is because they both point at the same object (Shape.prototype).What we need to do is to Object.create(Shape.prototype).)Now only shape1 has a color of blue, which is the desired effect.So we have our Shape type which spawns shape instances, but there are a few problems.The constructor object is visible and users can edit it. This will lead to unintended use of the type or instance, which needs to be avoided when desiging a good API. Therefore, we need to lock constructor so users are not able to override it or delete it. This brings us to the next section: Property Definitions.
  • #21 Since the purpose of a type is to create an instance out of the protoype, our Shape type needs a create function, that returns a new instance of a shape.(We need to Object.create the prototype, otherwise every instance of shape will point at the same prototype instead of being separate instances.)Next, we’ll create two instances of Shape and assign a blue color to one.[var shape1 = Shape.create();var shape2 = Shape.create();shape1.color = “blue”;&gt;shape1&gt;shape2](Both shapes have a color property of blue, and this is because they both point at the same object (Shape.prototype).What we need to do is to Object.create(Shape.prototype).)Now only shape1 has a color of blue, which is the desired effect.So we have our Shape type which spawns shape instances, but there are a few problems.The constructor object is visible and users can edit it. This will lead to unintended use of the type or instance, which needs to be avoided when desiging a good API. Therefore, we need to lock constructor so users are not able to override it or delete it. This brings us to the next section: Property Definitions.
  • #44 After we have sensed the user, the device and its surrounding environment comes UNDERSTAND. What it really means is we need to take all our senses together and marry them with data on the device and the cloud and interpret those senses in our app’s context. This could be as simple as reading PIM data on the device to all the way up to retrieving relevant data from the cloud. Let me show you what we’ve done to enable this.
  • #45 The purpose of this session is to go over patterns that help design good APIs using tools provided by ECMA5.