Post on 15-Jan-2015
description
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 propertyShape.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
• Enumerabletrue if the property is present while iterating through the object. (for prop in obj). Defaults to false.
• Configurabletrue if the property descriptor can be modified or property deleted on object.Defaults to false.
• Writabletrue if the property’s value can be changed? ( radius= 20)Defaults to false.
• ValueValue 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