ECMA5 approach to building JavaScript frameworks with Anzor Bashkhaz

Post on 15-Jan-2015

1.484 views 1 download

Tags:

description

Presented at SCREENS 2013 in Toronto. Details at fitc.ca/screens ECMA5 has given JavaScript a number of new ways to define and manipulate objects. In this session, attendees will learn how to combine Require.js and ECMA5’s object manipulation functions to create an inheritance model similar to class-based languages.

Transcript of ECMA5 approach to building JavaScript frameworks with Anzor Bashkhaz

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