Java Script Patterns

Post on 06-May-2015

288 views 2 download

Tags:

description

Refer to an IT book "O'Relly JavaScript Patterns".

Transcript of Java Script Patterns

JavaScript Pattern

allanhuang@eSobi.com

Agenda

About JavaScript Essential Practices Literals and Constructors Functions Object Creation Patterns Code Reuse Patterns

About Patterns

What’s Patterns? Not for copy-and-paste Useful abstraction Template or model for solving

Coding Patterns Design Patterns vs. Antipatterns

About JavaScript

Script language Interpreted language vs. Compiled language

Object-oriented Primitive types

number, string, boolean, null, undefined Native objects

Number, String, Boolean, Date, Array, Function… User-defined

About JavaScript

Prototype-based language No Classes

vs. Class-based language Prototype

Alteration prototypes during run-time

Dynamic typing Values have types but variables do not

About JavaScript

First-class functions Function literals or Function types Functions as first-class objects

Own properties and methods

ECMAScript 5 (be called ES5, for short) Vs. ECMAScript 3 (ES3) Strict mode Library extensions

Tools for JavaScript

Firebug If (console && console.firebug)If (console && console.firebug) Object inspection

console.dir(object)console.dir(object) Timing and profiling

console.time(message)console.time(message) Stack traces

console.trace()console.trace() Nested grouping

console.group(message)console.group(message)

Tools for JavaScript

Code Quality Tool JSLint

Strict mode-compliant Web Page Performance Diagnostics Tool

YSlow from Yahoo! Page Speed from Google

Books about web pages tuning High Performance Web Sites, O’Reilly Even Faster Web Site, O’Reilly

Essential Practices

Essential Practices

Maintainable code Readable Consistent Predictable Looks as be written by Same Person Documented

Essential Practices

Global variables Minimize Globals

Always use var to declare variables Single var Pattern

Other ways… Namespacing pattern Self-executing immediate function

Can Global Variables be delete? Hoisting problem

Essential Practices

For Loop Iterate over arrays or array-like objects

Cache the length of the array ++++ and ---- vs. i += 1i += 1 and i -= 1i -= 1 Use one less variable Count down to 0

For-in Loop Iterate over non-array objects

hasOwnProperty()hasOwnProperty() method

Essential Practices

Augmenting Built-in Prototypes Unpredictable code Except…

Future ECMAScript version or JavaScript implementation

Custom property or method does not exist

Switch Pattern Avoiding Implied Typecasting

==== and !=!= vs. ====== and !==!==

Essential Practices

Avoiding eval()eval() setInterval(), setTimeout()setInterval(), setTimeout() and new Function()new Function() eval()eval() Interfere with the scope chain Function()Function() is like a sandox JSON.parse()JSON.parse() method

Use parseInt() parseInt(string, radix)parseInt(string, radix) +”08”+”08” Number(“08”)Number(“08”)

Code Convention

Curly Braces {…}{…} Always use {…}{…} if only one statement in an ifif or a forfor Opening Brace Location

White space for (var i = 0; i < 10; i += 1) {…}for (var i = 0; i < 10; i += 1) {…} for (var i = 0, max = 10; i < max; i += 1) {…}for (var i = 0, max = 10; i < max; i += 1) {…} var a = [1, 2, 3]var a = [1, 2, 3] var o = {a: 1, b: 2}var o = {a: 1, b: 2} myFunc(a, b, c)myFunc(a, b, c) function myFunc( ) {…}function myFunc( ) {…} var myFunc = function () {…}var myFunc = function () {…}

Naming Convention

Camel case constructors functions methods variables: all lowercase words with underscore

Constants: use all capital letters Global variables: use all capital letters

Naming Convention

Private scope Underscore prefix(?)

e.g. _getName()_getName() properties methods

The Next…?

Write Comments Write to Be Read Write API Docs

Peer Reviews Tools for code better

Run JSLint Minification

Yahoo! YUI Compressor Google’s Closure Compiler

Literals and Constructors

Object Literals

var object = { };var object = { }; Change the values of properties and methods Delete / Add properties and methods

Blank object / Empty object inherited from Object.prototype

Object constructor Scope resolution

Look up the scope chain from the place you calling nenew Object()w Object()

Constructor

Add reusable methods to the prototype, but not the constructor function

Return this or any other object Invoke the constructor without newnew Return another object: that

Prototype is not available Self-Invoking constructor

Array Literal

var array = [ ];var array = [ ]; Array.isArrayArray.isArray method

Added from ES5 Array toString()

[object Array] Object toString()toString()

[object Object]

JSON

Syntax Similar to Object Literal Property names are wrapped in “…” No Functions Literal No Regular Expression Literal

JSON.parse()JSON.parse() / JSON.stringify()JSON.stringify() Browser build-in native methods jQuery.JSON YUI.JSON

Regular Expression Literal

var re = /pattern/gmi;var re = /pattern/gmi; var re = new RegExp(‘\pattern\’, ‘gmi’)var re = new RegExp(‘\pattern\’, ‘gmi’)

Global matching: g Multiline: m Case-insensitive matching: I Same regular expressions if their expressions are

equal each other

Primitive Wrappers

Built-in constructor Number()Number() String()String() Boolean()Boolean()

Useful methods work on primitives that is temporarily converted to an object

Primitives cannot be augmented with properties or methods

Error Objects

Error()Error(), SyntaxError()SyntaxError(), TypeError()TypeError() name, message

Throw…Catch Custom error object

Constructor Syntax

Functions

Function

2 very important features They are Objects They provide Local Scope

Can be… Created dynamically, Assigned to variables Augmented, Deleted in a few special cases Passed as arguments, Returned by other

functions Their own properties and methods

Function

Named Function Expression var var addadd = function = function addadd() {…}() {…};; Incompatible with IE

Unnamed Function Expression var var addadd = function () {…} = function () {…};; Function Expression Anonymous Function

Function

Function Declaration function function addadd() {…}() {…} Inside other functions or the global scope

Function’s name Pros

Debugging Recursive call

API Patterns

Help you provide better and cleaner interface to your functions Callback Pattern Configuration Objects Returning Functions Currying

Initialization Patterns

Help you perform initialization and setup tasks without polluting the global namespace Immediate Function Immediate Object Initialization Init-Time Branching

Performance Patterns

Help speed up the code Memoization Self-Defining Functions

Callback Patterns

Callback Function Template Method

Scope Pass the object that callback belonged to Pass the method (callback) as string

Asynchronous Event Listeners Cons

Out of order Timeout

setTimeout()setTimeout() setInterval()setInterval()

Function Patterns

Returning Function Return another function Use Closure to store private data

Self-Defining Function Create a new function assign to the same variable Initial work to be done only once Lazy function definition Original function will be lost when it redefined

Function Patterns

Immediate Function Self-Invoking, Self-Executing Execute a function as soon as it is defined

((function () {…}function () {…}());()); ((function () {…}function () {…})();)();

A scope sandbox for initialization code Pass arguments to immediate functions

Function Patterns

Immediate Function Return values

var result = var result = ((function () {return…}function () {return…}());()); var result = var result = ((function () {return…}function () {return…})();)(); var result = function () {return…}var result = function () {return…}();();

Bookmarklet Self-contained modules

Function Patterns

Immediate Object Initialization init() after object is created

(({…}{…})).init.init();(); (({…}.init{…}.init());());

DrawbackDrawback MinificationMinification No return values

Init-Time Branching Load-time branching e.g. Browser sniffing

Function Patterns

Memoization Pattern Use Properties to store Cached data

arguments.calleearguments.callee

Configuration Objects Substitute for a set of passed arguments

Curry Partial Application Currying

When to Use Currying?

Object Creation Patterns

Object Creation Patterns

Namespace pattern A generic namespacenamespace function All capital letters Drawbacks

A bit more to type Only global instance Long resolution lookup

Object Creation Patterns

Declaring Dependencies Declare the modules your code relies on at the

top of your function or module Realize the specific JS files are needed Easy to find and resolve dependencies Perform global symbol resolution only once

Private, Protected, or Public

Private Members Using Closure to access private members

Function Declaration as private functions

Privileged Methods Public methods have access to the private

members (properties or methods) A returned private variable can be modified if it’s

an object or array (Passed by Reference)

Private, Protected, or Public

Private members always are created when the constructor is invoked Add public reusable members to the prototype

property of the constructor Revelation pattern

Reveal private functions as public methods

Module Patterns

Provide structure and help organize your code as it grows

In common use all over our web applications Combine the following patterns

Namespaces Immediate Functions Private and Privileged members Declaring dependences

Module Patterns

Reveal Module Pattern Return the object has triggers of private functions

Modules that Create Constructors Return the constructor function

Importing Globals into a Module

Sandbox Pattern

Drawbacks of Module pattern No way to have 2 versions of the same

application or library Long, dotted names to type and resolve at

runtime A Global Constructor Adding Modules

Static Members

No instance-specific Public Static member

Be accessible outside via Constructor

Private Static member Not accessible outside Using Closure feature

Object Constants

All capital letters Math.PIMath.PI Number.MAX_VALUENumber.MAX_VALUE

General-Purpose Constants object set(name, value)set(name, value) isDefined(name)isDefined(name) get(name)get(name)

Chaining Pattern

Call methods on an object after the other Pros

Save some typing Create more concise code

Cons Debug code more difficult

Always return thisthis if your method has no return value

method() Method

Help you define the whole “class” with a single statement

Drawback Debug code more difficult Add methods to thisthis is inefficient

Methods are re-created with every instance Consume more memory

Reusable methods should be added to the prototypeprototype property of the constructor

Code Reuse Patterns

To Reuse Code…

Inheritance That is one way for us to reuse code, but not the

only way Composition / Delegation

Prefer object composition to class inheritance Prototype Inheritance

Prototype Constructor

The Default Pattern (#1) Child.prototype = new Parent( );Child.prototype = new Parent( );

The Default Pattern (#1)

Benefits Inherit parent properties and parent prototype

members Drawbacks

Inherit parent properties added to thisthis and the child prototype properties

Can’t pass parameters to the child constructor General rule of thumb with constructors

Reusable members should be added to the prototype

Rent-a-Constructor (#2) function Child (…) {function Child (…) {

Parent.apply(this, arguments); Parent.apply(this, arguments);}}

Rent-a-Constructor (#2)

Benefits Borrowing Constructor Pattern Only inherit parent properties added to thisthis

inside the parent constructor Drawbacks

Can’t inherit parent prototype members Multiple Inheritance by Borrowing

Constructors

Rent and Set Prototype (#3) function Child (…) {function Child (…) {

Parent.apply(this, arguments); Parent.apply(this, arguments);}}Child.prototype = new Parent( );Child.prototype = new Parent( );

Rent and Set Prototype (#3)

Benefits Combine #1 and #2 patterns

Drawbacks Parent constructor is called twice Parent members get inherited twice

Share the Prototype (#4) Child.prototype = Parent.protoype;Child.prototype = Parent.protoype;

Share the Prototype (#4)

Benefits Child prototype is equals to parent prototype All objects share the same prototype

Drawbacks One child modified the prototype that affects all

parents

A Temporary Constructor (#5) var F = function( ) { };var F = function( ) { };

F.prototype = Parent.prototype;F.prototype = Parent.prototype;Child.prototype = new F( );Child.prototype = new F( );Child.uber = Parent.prototype;Child.uber = Parent.prototype;Child.prototype.constructor = Child;Child.prototype.constructor = Child;

A Temporary Constructor (#5)

Benefits A proxy function between child and parent Parent constructor members adds to thisthis are n

ot inherited Holy Grail version

Storing super (uberuber) class Resetting constructor pointer Use an immediate function to store proxy functi

on in it’s closure

Klass

Emulating Class A generic klassklass function

Implementation Create a Child( )Child( ) constructor function Inherit parent via Holy Grail pattern Add parent members to child prototype

Prototypal Inheritance function object (o) {function object (o) {

function F( ) { } function F( ) { } F.prototype = o; F.prototype = o; return new F( ); return new F( );}}

Prototypal Inheritance

Feature Modern Classless Pattern A generic objectobject function Create a child object gets its functionality from

parent object Addition to ES5

var child = Object.create(parent);var child = Object.create(parent);

Inherit by Copying Properties

Feature A generic extendextend function Create a child object gets its functionality from

parent object by copying A deep copy version

extendDeepextendDeep

Mix-ins

Feature A generic mixmix function Create a child object gets its functionality from an

y number of parent objects by copying Multiple Inheritance Implementation

Borrowing Methods

Feature A generic bindbind function Use some methods without inheriting other metho

ds A common use for this pattern

Array.slice.call(arguments)Array.slice.call(arguments) Array( ).slice.call(argument)Array( ).slice.call(argument)

Addition to ES5 Function.prototype.bind( )Function.prototype.bind( )

Design Patterns

Singleton

Purpose Creating only one object of a “class”

New instance via Object Literal New instance via Constructor

Store in a Global Variable Cache in a Static Property of the constructor Wrap in a Closure

Private Static Member pattern Self-Defining Functions

Factory

Purpose A method that creates objects of type specified as

a string at runtime Map object types to the constructors that

create different objects Built-in Object Factory

new Object(?)new Object(?)

Iterator

Purpose Providing an API to loop over and navigate

around a complex custom data structure Additional convenience methods

rewind( )rewind( ) current( )current( )

Decorator

Purpose Tweaking objects at runtime by adding functionalit

y from predefined decorator objects Undercorating / Undoing a decoration

Implementation Using a Array It’s no need to use Inheritance

Decorator Implementation

Strategy

Purpose Keeping the same interface while selecting the be

st strategy to handle the specific task (context) The validatorvalidator is generic and could be kept lik

e this for all validation use cases

Facade

Purpose Providing a more convenient API by wrapping co

mmon methods into a new one Handle browser events

stopPropagation( )stopPropagation( ) preventDefault( )preventDefault( )

Proxy

Purpose Wrapping an object to control the access to it,

with the goal of avoiding expensive operations Proxy serves as a guardian of the “real

subject” and tries to have the real subject do as little work as possible

Proxy As a Cache More less Network Round-trips Memorization Pattern

Proxy As a Cache

Mediator

Purpose Promoting loose coupling and then helping

improve maintainability Independent colleagues don’t communicate

directly, but through a mediator who notifies the change to any other colleagues

Mediator in Keypress Game

Observer

Purpose Loose coupling by creating “observable” objects

that notify all their observers when an interesting event occurs

Subscriber (Observer) / Publisher (Subject) Publisher has important methods

subscribe( )subscribe( ) unsubscribe( )unsubscribe( ) publish( )publish( )

DOM and Browser Patterns

Separation of Concerns

3 main concerns in web application Content - HTML Presentation - CSS Behavior - JavaScript

In Practice… Page is still readable if CSS is off Page perform main purpose if JavaScript is off Not using inline event handlers or stylestyle attributes Using meaningful HTML elements

DOM Access

Bottleneck DOM is separated from JavaScript engine

Good Parts… Avoiding DOM access in loop Assigning DOM reference to local variables Using selectors API

document.document.querySelector(querySelector(“#widget”“#widget”));; document.document.querySelectorAll(querySelectorAll(“.widget”“.widget”));;

Cache the length of HTML collections document.document.getElementByIdgetElementById(“id”)(“id”) is fastest way

DOM Manipulation

Bottleneck Modify DOM to repaint the browser’s screen and r

ecalculate element’s geometry Batch the changes and performing them outsi

de of the livelive document tree Use a document fragment to contain new nodes

var frag = document.var frag = document.createDocumentFragment()createDocumentFragment();; Make all change to the Clone of root of subtree

var newnode = oldnode.var newnode = oldnode.cloneNode(cloneNode(truetrue));; oldnode.oldnode.parentNode.replaceChildparentNode.replaceChild(newnode, oldnode);(newnode, oldnode);

Events

Bottleneck Event handling in IE (version < 9) and W3C-confo

rming implementations is different Access event

Passed to Callback event handler Use onclickonclick property through window.eventwindow.event

e = e || e = e || window.eventwindow.event;;

Access target of event src = e.src = e.targettarget || e. || e.srcElementsrcElement;;

Event Handling

W3C-conforming Event Capturing Cancel Event Propagatio

n e.e.stopPropagationstopPropagation();();

Prevent default action e.e.preventDefaultpreventDefault();();

IE (version < 9) Event Bubbling Cancel Event Propagati

on cancelBubblecancelBubble = = truetrue;;

Prevent default action returnValuereturnValue = = falsefalse;;

Event Delegation Pattern

Benefits Suitable for Event Bubbling Reduce the number of event listeners attached

to separate nodes Better performance and cleaner codes

Drawbacks Filter out the uninteresting events

Use 3rd JavaScript library

Event Handling 3rd-party API

jQuery version 1.0 ~ 1.3

$(target).$(target).bindbind(event, callback);(event, callback); $(target).$(target).triggertrigger(event);(event); $(target).$(target).oneone(event, callback);(event, callback); $(target).$(target).livelive(event, callback);(event, callback);

version 1.4.2 ~ $(container).$(container).delegatedelegate(target, event, callback);(target, event, callback);

Yahoo! YUI Y.Y.delegatedelegate(event, callback, (event, callback, containercontainer, target);, target);

Long-Running Scripts

Issue Browser complains a Long-Running Script and as

k user if it should be stopped Solutions

setTimeout()setTimeout() Use 1ms timeout chunks cause task to complete slowl

y overall, but browser UI will remain responsive WebWorkersWebWorkers

Web workers provide background thread support in the browser

Remote Script

AJAX (Asynchronous JavaScript and XML) XMLHttpRequest Restricted same-domain

JSONP (JSON with Padding) HTML Script element Injection

script.src = url;script.src = url; Execute a client-side callback with server-side JS

ON data passed from different domain Unrestricted cross-domain

Remote Script

Frame HTML iFrame element Injection

iframe.src = url;iframe.src = url; Image Beacons pattern

Send data to server but not expecting a response new Image()new Image().src = “http://...”;.src = “http://...”; Response with 1x1 GIF image or “204 No Content204 No Content”

HTML5 Cross-document messaging

otherWindow.otherWindow.postMessagepostMessage(string, targetOrigin);(string, targetOrigin);

Deploying JavaScript

Combining Scripts Benefits

Speed up Page Loading Drawbacks

More preparations before deploying into production Help from Ant tool

Lose some of the caching benefits Spilt up to 2 bundles: barely change and hardly change

Come up with some naming and versioning pattern for bundle

Deploying JavaScript

Minifying Yahoo! YUI Compressor Google’s Closure Compiler

Compressing Enable GZIP compression in server-side

Expires Header Stay files in browser cache as far as possible Rename files if they have been changed

Construct or Using CDN Google, Microsoft, Yahoo! hosts popular libraries

Using Popular CDN

Benefits Decreased Latency

Clients will automatically target the closest available server in the network

Increased Parallelism Eliminate one request to your site, allowing more of

your local connect to download in parallel Better Caching

Clients will only need download it once if it had been visited on another website using the same CDN

Loading Strategies

Minimize blocking effect Place <script> at the closing </body> element

HTTP Chunking Non-blocking downloads *.js

Load script with an AJAX and eval()eval() it as a string Using deferdefer / asyncasync attributes of <script> Using Dynamic <script> Pattern

Append this dynamic <script> to <head> or <body> Also insert this dynamic <script> before the first availa

ble <script>

Dynamic <script> Pattern

Drawbacks Any other <script> can’t rely on the main *.js bein

g load on the page Solution

Using anonymous function to wrap separate inline scripts into a function and add each function into an empty array

Loop through this array in main script and execute all of them

Better Dynamic <script> Pattern

Lazy Loading Load external *.js unconditionally after page load

event Loading on Demand

Load only the parts *.js that are really needed Create a method that loads <script> dynamically

and execute a callback when <script> is loaded In W3C-conforming, subscribe loadload event In IE (version < 9), subscribe readystatechangereadystatechange event

and look for a readystatereadystate === “loadload” or “completecomplete”

Better Dynamic <script> Pattern

Preloading JavaScript Load external *.js are not needed on current page

but on following pages without parsing and executing *.js immediately

This works not only for *.js, but also *.css and images, e.g. *.jpg, *.png etc.

Drawbacks The presence of user agent sniffing Some browsers probably have a separate cache for i

mages, so preloading *.js or *.css will not be used

Better Dynamic <script> Pattern

Preloading JavaScript Create a method using init-time branching pattern

to handle browser sniffing Using invisible <object> in W3C-conforming Using new Image()new Image().src.src in IE

Conclusion

Q&A