Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

notes for 'JavaScript Patterns' by Stoyan Stefanov

NotificationsYou must be signed in to change notification settings

csabapalfi/javascript-patterns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 

Repository files navigation

Notes for JavaScript Patterns by Stoyan Stefanov

1. Introduction

patterns in general

  • solution to a common problem
  • don't re-invent the wheel if you don't have to
  • provide a level of abstraction (models - all is wrong, some are useful)
  • common patterns help communication
  • this book covers
    • design patterns: (generally simpler) JS implementation of GoF patterns
    • coding pattens: JS specific pattern and good practices (main topic of the book)
    • antipatterns: common approach causing more problem than it solves

(almost) everything is an object

  • only five primitive types are not objects: number, string, boolean, null, undefined
  • first three has object representation with primitive wrappers
  • functions are objects too
  • a var is an object
    • becomes a property of the internal Activation Object or global object if it's global
    • var itself is object-like, has properties called attributes (exposed since ES5)
    • attributes determine if var can be changed, deleted or enumerated infor-in

what's an object?

  • an object is simply a collection of named properties (key-value pairs)
  • an object can have methods - simply when a value of a property is a function
  • and object can be modified (almost) anytime - properties added, removed, updated
  • an object is
    • either native: user defined ({}) or built-in (Date) -
    • native objects are described in the ES standard
    • or host object (window) - defined by the host environment

no classes

  • no classes, unlearn if you worked with another OO language before
  • usually you just start with empty object and add properties to it
  • prefer composition over inheritance

prototypes

  • one way of achieving inheritance, but nothing special
  • prototype is just object property that gets added to every function
  • prototype property points to a new empty object
  • prototype object almost identical to object literal or new Object() but
  • but constructor property points at the function you're creating not the builtin Object()

environment

  • JS programs need an environment to run
  • the browser is the most common one
  • most patterns in the book are environment-agnostic
  • environments can provide their own host objects
    • which might have unexpected behaviour
    • not defined in the ES standard

EcmaScript 5

  • core javascript is based on the EcmaScript standard
  • ES3 was accepted in 1999, ES4 was dropped, ES5 2009
  • most important addition: strict mode
    • trigerred by a'use strict'; - backwards compatible
    • once per scope - that function is executed in a strict subset of the language
    • error is thrown if a non strict allowed feature is used
  • the plan is that future version will only support strict mode

JSLint/JSHint

  • Javascript is an interpreted language with no compiler to help spotting errors
  • JSLint and JSHint are static code analysis tools
  • JSLint is really strict but JSHint is more configurable
  • All examples in the book pass JSLint

console

  • theconsole object is not part of the language but available in most environments
  • Firebug in Firefox, Chrome Dev Tools in Chrome, standard I/O in Node.js, IE8+ Developer Tools
  • console.log - prints all parameters passed to it
  • console.dir - enumerates object and print all properties
  • when testing in browser console they log output by default

chrome dev console

  • log XHR
  • console.time()/console.timeEnd()
  • console.dir()/dir()
  • inspect() / $0
  • $$
  • monitorEvents() // mouse, key
  • keys()/values()
  • copy()

2. Essentials

minimizing globals

  • JavaScript uses functions to manage scope
  • variables declared within a function are local and not visible outside
  • global variables are declared outside of functions or used without being declared
  • every JS environment has a global object - accessible viathis outside of any function
  • every global variable becomes a property of the global object
  • in browser the global object has a property calledwindow pointing to the global object itself

problems with globals

  • shared among all the code in your app or webpage
  • danger of name collisions (especially with third-party code)
  • easy to create globals involuntarily: implied globals
  • implied globals: undeclared var is global
  • chained declaration also results in implied globals unless vars are declared in advance
  • you might accidentally overwrite existing host object properties
  • globals created with var outside of any function can't bedeleted
  • ES5 strict mode doesn't allow undeclared variables

access to the global object

  • pass a reference to this from global scope to your function
  • non-strict mode: any function invoked (not withnew) hasthis pointing at the global object

single var pattern (nope)

  • the world has moved on: seethis blog post
  • single var statement at the top of your functions
  • single place to look for all the vars needed by your function
  • prevents logical errors when var is used before it's defined (hoisting)
  • might be good practice to initialize them with some defaults
    • to avoid undefined
    • also communicates the intended use

hoisting

  • multiple var statements (anywhere in a function) act as if they were at the top

caching array length in for loops (?)

  • for cache array lengthfor (var i, max = arr.length; i < max, i++)
  • unless length can change

for in and hasOwnProperty when needed

  • for in - filter things coming down the prototype chain
for(propinobj){if(obj.hasOwnProperty(prop)){}}
  • unless you know and can trust the object you're dealing with

don't augment builtin prototypes

  • augmenting the prototype property of constructor functions is powerful
  • but hurts maintainability when done on builtin prototypes
  • when you absolutely need to: communicate with your team and check if property already exists
if(typeofObject.prototype.myMethod!==function){    Object.protoype.myMethod=function(){// implementation}}

switch

  • align eachcase withswitch
  • indent code within eachcase
  • always endcase withbreak;
  • avoid fallthroughs (no break)
  • end the switch withdefault:

avoid implied typecasting

  • JavaScript implicitly typecasts variables when you compare them
  • always use=== and!=== as they check types as well

eval() is evil

  • executing any String as JavaScript, seriously?
  • use[] to access dynamic properties
  • use JSON.parse for AJAX responses
  • always usefunctions withsetTimeout andsetInterval (instead of Strings)
  • try not to usenew Function() as it's similar toeval

specify radixparseInt() (?)

  • parseInt() gets a numeric value from a String
  • has an optional radix parameter which shouldn't be omitted (in ES3)
  • ES3parseInt('08') gets confused and treats numbers starting with 0 as octals

code conventions

  • more important to agree and consistently follow than what the exact details are
  • indent everything within curly braces
  • always use curly braces (even when optional: for, if)
  • avoid errors or confusion by automatic semicolon insertion
    • always put opening curly braces on the same line as the previous statement
    • always use semicolons
  • generic and consistent use of spaces makes code more readable
  • use vertical spacing too - blank lines to separate units of code

naming conventions

  • Capitalize constructor functions to differentiate them
  • use camelcase in function and variable name to separate words
  • all caps for constants (not expected to change even though this can't be enforced until ES6 const)
  • underscore (_ or__) prefix (and/or suffix) for private API

write to be read

  • keep comments up to date if you write them
  • jsDoc and YUIDoc can generate API docs from comments

minify in production

  • any code delivered to the browser should be minified to improve performance
  • Uglify, Closure Compiler, YUI Compressor

Run JSLint/JSHint

  • on edit/save

3. Literals

  • {},[] and// is preferable
  • instead of usingnew Array(),new Object(),new RegExp()
  • more concise, less error-prone

Object literal

  • object are simple maps or key value pairs
  • properties: values that are primitives or other objects
  • methods: values that are functions
  • custom objects (or user defined native objects) are mutable at any time
  • you can add/remove functionality as you go
vartest={};test.message='hello';test.hello=function(){console.log('hello');};deletetest.hello;
  • but you're not required to start with an empty object
vartest={message:'hello'};
  • note that empty object also inherit everything fromObject.prototype
  • object literal notation emphasises that objects are just mutable hashes
  • no need for classes
  • also there's no need for scope resolution like with constructor
  • (scope resulotion is required to look for constructor with same name in the scope chain)

Object constructor catch

  • there's no reason to use new Object() but legacy code might rely on an additional 'feature'
  • Object constructor accepts a parameter
  • and might delegate to another builtin constructor depending on the passed in value

Custom constructor functions

  • just a function
  • when invoked with new:
    • an empty object is created referenced bythis
    • this inherits the prototype of the function
    • properties and method are added tothis
    • the newly created object referenced bythis is returned
  • reusable members such as methods should go to the prototype
  • this is not really initalized with an empty object
  • butthis actually is a result of Object.create() called with prototype
  • return value can be changed by explicitly returning a different object
  • non-Object return values are silently ignored andthis is returned

enforcing new

  • when a constructor is called without newthis points at the global object
  • above is no longer true in strict mode,this won't point at the global object
  • always uppercase the first letter of constructor functions (and lowercase function names)
  • also when not using the prototype you can just return a new object literal (that)

self-invoking constructor

  • another pattern to enforce new
  • calls itself with new if not called with new
functionWaffle(){if(!(thisinstanceofWaffle)){returnnewWaffle();//...}}
  • alternative to above not hardcoding constructor name (not in ES5 strict mode!)
if(!(thisinstanceofarguments.callee)){returnnewarguments.callee();}

arguments

  • inside every function an object called arguments is created
  • containing all the parameters passed to the function when it was invoked
  • arguments has a property named callee which points back at the called function
  • arguments.callee is not allowed in ES5 strict mode

Array literal

  • [] is preferred tonew Array()
  • unexpected Array constructor behaviour:
    • called with single number, uses the number as length
    • if number is a float, results in RangeError as it's not valid array length
    • hack for repeating strings:new Array(256).join(' '); //255 spaces

checking Array-iness

  • typeof with array operands returnsobject
  • before ES5 - checking for length or slice property
  • ES5 introduced .isArray method
  • alsoObject.prototype.toString() returns"[object Array]" (instead of"[object Object]")

JSON

  • combination of object and array literal notation
  • but property names and Strings have to be wrapped in double-quotes
  • no functions or regex literals
  • ES5 JSON.parse and JSON.stringify

Regex literal

  • // is preferred tonew RegExp()
  • shorter and no need to escape quotes or double-escape backslashes
  • /<regex>/<flags> - flags (g)lobal, (m)ultiline, case (i)nsensitive
  • use new RegExp() if the pattern is not known, and constructed runtime as a String
  • before ES5 the literal created only one object even when called repeatedly
  • (same object is a problem as it has properties like lastIndex set)
  • starting from ES5 regex literal returns new object

primitive wrappers

  • JS primitives: number, string, boolean, null and undefined
  • number, string and boolean have primitive wrapper
  • primitive wrapper objects come with useful methods like .toFixed() or substring()
  • these methods work on primitive (variables) as well, converted temporarily
  • only use wrapper object when you need to augment a value and persist state (do you really need to?)
  • attempting to augment primitive value doesn't result in error but won't persist state
  • new wrapper constructor converts argument to primitive value

Error object

  • JS has built-in Error constructors to be used withthrow
  • Error(),SyntaxError(),TypeError()
  • these error object havename andmessage properties
  • Error constructors work the same way when called with or withoutnew
  • throw works with any object - you can come up with custom error objects

new Date()

  • one of the only builtin constructors you actually want to use

4. Functions

functions are first class objects

  • can be created dynamically at runtime
  • can be assigned to vars, have their references copied to other vars
  • can be augmented and deleted (except for some special cases)
  • can be passed as arguments to other functions or returned by them
  • can have their own properties and methods
  • they's just another object with a special feature: they're executable
  • (but don't usenew Function(arguments, code) as it's bad as eval)

functions provide scope

  • in JS there's no curly braces local scope
  • blocks don't create a scope
  • there's only function scope
  • any var defined within function is only visible in that function
  • any war within an if block or for loop is local only to the wrapper function
  • if there's no wrapper function then it becomes global

terminology

  • named function expression
varadd=functionadd(a,b){ ...}
  • if you skip the name: (unnamed) function expression or anonymous function
varadd=function(a,b){ ...}
  • using anonymous function won't affect definition or invocations etc.

  • but the name property of the function object will be undefined

  • careful, that's what's shown in stacktraces

  • (the name property isn't (wasn't?) part of the ES standard)

  • function declaration:

function(a,b){ ...}
  • no semicolon required for function declarations
  • can only appear in program code: inside bodies of other functions or global space

name property

  • use named function expression or declaration as it sets name property
  • allows function name to be displayed properly in debugger

literal and using a different var name

  • function literal is an ambiguous term and should be avoided
  • giving a function a name and assigning it to a var with a different name might not work in older browsers

function hoisting

  • for function declarations the function definition also gets hoisted
  • for function expressions it's only the variable that gets hoisted
  • function expressions are not callable before their definitions

callback pattern

  • function reference (callback) can be passed into another function
  • the other function can execute (call back) the passed in function when appropriate

callback method vs function

  • careful with usingthis if callback function is a method of an object
  • as callback is not called as method but a function this points at either global or the callers this
  • a workaround is to pass to object in a second parameter, thencallback_function.call(obj, args)
  • or pass object and method name as string thenvar callback_function = obj[callback_name]

callback examples

  • async event handlers in the browser accept callbacks (addEventListener)
  • setTimeOut andsetInterval also accepts callbacks

returning functions

  • functions are objects so they can be used as return values
  • a function can return another more specialized function or create one on demand

self defining function pattern

varselfDefining=function(){//e.g. do some prep you only got to do onceselfDefining=function(){// new function body to overwrite old one}}
  • another name for this is lazy function definition
  • any properties previously set are cleared when redefining
  • also if function used with a different name (assigned to another var)
  • the var with the different name will use the non-redefined function

immediate function

  • execute function as soon as it's defined
(function(){//...}());
  • wrapped in parens so it's clear it's not a function declaration (but expression)
  • scope sandbox for initialization code
  • not leaking any variables
  • global objects can be passed as parameters
  • so don't have to use window inside immediate function
  • but don't pass too many vars to keep it readable
  • scope of the immediate function can be used to store private data
  • and then an object with public methods can be returned
  • can be used to implement self-contained modules
  • other names: self-invoking, self-executing

immediate Object initialization

({property:'value'method:function(){ ...}init:function(){ ...}}).init();
  • wrapped in parens so that it's clear it's not a code block but object
  • same purpose as immediate function above but more structured
  • private helper methods are clearly distinguishable
  • might not be trivial for minifiers to shorten inner helper method names
  • no reference to the object is available after init
  • unless you doreturn this; in init

init-time branching

  • also known as load-time branching
  • if a condition is not going to change (e.g. browser feature)
  • only check it once in your program in your init code

function properties and memoization

  • functions are objects and can have properties
  • all functions have a length property (number of arguments it accepts)
  • memoization: caching the return value of a function
  • you can add a property named cache - object
  • cache object: keys - argument, values - return value
  • multiple arguments - serialize them (e.g. JSON.stringify) to get a single value

options/configuration object

  • when a function needs to be called with many parameters just use an object
  • parameter or doesn't matter, optional parameters can be skipped
  • easier to read, add remove parameters
  • but you need to remember parameter names, older minifier might not shorten names properly

function application

varhello=function(message){ ...};hello.apply(null,['hey!']);
  • a function can be applied usingFunction.prototype.apply
  • first argument is an object to bindthis to
  • second argument is an array of arguments
  • in non-strict mode if first argument is null then it'll point at the global object
  • Function.prototype.call is just syntactic sugar over apply
  • call expects parameters as normal parameter list instead of an array

function binding

  • Function.prototype.bind has the same signature as.call
  • creates a new function bound to the object and optional parameters passed in

partial application / currying

  • call a function with less than all of it's arguments
  • and return a function expecting the rest of the arguments
  • this transformation of function is called currying or schonfinkelizing
  • use when find yourself calling a function with same arguments
// basic curry examplefunctioncurriedAdd(x,y){if(y===undefined){returnfunction(y){returnx+y;}}returnx+y;}// currying with bindvarcurried=add.bind(undefined,10);curried(5);

5. Object creation patterns

namespace pattern

  • reduce number of globals and name collisions (without excessive prefixing)
  • create a single global object for your app/lib
  • change all your functions and variables to become a property of that object
varmyApp=myApp||{};// prevent overwriting if namespace split across filesmyApp.myFunc=function(){ ...}

prevent overwriting

  • prevent overwriting if namespace split across files
varmyApp=myApp||{};

namespace function

  • can create a function to turn a dot separated string to nested objects
myApp.namespace=functionnamespace(ns){varparts=ns.split('.').slice(1);// split on dot, skip first itemvarparent=myApp;parts.forEach(part,i){if(typeofparent[part]==='undefined'){parent[part]={};}parent=parent[part];}}myApp.namespace('myApp.this.is.nested')===myApp.this.is.nested;

declare dependencies at the top

functionmyFunction(){vardom=myApp.utils.dom;varevent=myApp.utils.event;}
  • shorter to type module names afterwards
  • deps in one place
  • some minifiers won't shorten global var names

private members with closures

  • constructor function create a closure
  • any variables part of constructor closure are not visible outside of it
functionPerson(){varsecret='hey';return{doIt:function(){// can see secret}}}varme=newPerson();me.secrect===undefined;secret===undefined;me.doIt();//does it
  • privileged methods are the ones declared within the constructor
  • privileged methods have access to private members
  • old versions of Firefox allowed access to private scope
  • internal arrays/objects are still modifiable via reference
  • make sure you return a new object with only the properties needed by caller
  • or copy your objects/arrays (with utility methods)

private properties on prototype

  • properties are re-created every time an object is initialized
  • shared properties of prototype can also be made private with the same pattern
Person.prototype=(function(){//all person sharing the same secretvarsecret='hey';return{doIt:function(){// can see secret}}}());

revealing module pattern

  • revealing private methods by assigning them to properties of the returned object
  • can name the property differently to the internal function
  • can expose internal function under more than one names
Person.prototype=(function(){functionsayHello(){}return{greeting:sayHello}}());

module pattern

  • combination of above:
    1. define a namespace
    2. assign an immediate function to it
    3. which declares dependencies at the top
    4. has private methods
    5. and returns an object revealing public API of the module
    6. globals can be passed in parameters to the immediate function
  • a module can create a constructor as well
  • if you return the constructor function instead of an object

sandbox pattern

  • addresses some namespace drawbacks: single global var, long dotted names
newSandBox('dependencies','here',function(box){// your code here});
  • you have a single global constructor
  • passed in callback function is you isolated environment
  • you initiate multiple Sandbox object and even nest them
  • you can name the constructor appropriately (instead of Sandbox)
  • YUI (now dead) used this

implementing the sandbox pattern

  • as the Sandbox function is an object we can add a modules (object) property to it
  • add required modules tothis
  • then call callback withthis
  • the callback is the users sandbox and get populated with the requested functionality

static members

  • just add property to constructor function - as that's an object as well
  • (normal methods are added to the prototype or the returned object)
  • you can't call static methods on instance unless you add an alias to prototype
  • when aliasing static method on prototype - careful if you usethis within the method

private static members

  • return constructor function via an immediate (self invoking) function
  • variables within the immediate function are invisible outside (as usual)

constants

  • no real way to do it in ES5
  • just naming convention: all caps, and also worth making sure they're static
  • const keyword coming in ES6

chaining

  • methods (that may not have a meaningful return value) returning this
  • allows calling methods in a chain in a single expression
  • pros: save some typing, more concise, small and focused methods
  • cons: may get a bit harder to debug - lot happening on a single line
  • JQuery uses it

method() method

  • making JavaScript a bit more class-like (which is probably a bad idea)
  • some syntactic sugar to add functions to the prototype property of the constructor
varPerson=fucntion(){...}.method('methodName',function(){ ...});

6. Code reuse patterns

Prefer composition over inheritance.

classical inheritance

  • play on the word 'class', nothing to do with the word classical
  • JavaScript has no classes but constructor functions make same people think that
  • use the term constructor function
  • probably a bad idea but worth knowing about

the prototype chain

  • can think of objects as blocks of memory
  • all objects from the same constructor point at same prototype object
  • can think of it as if they were pointing at it via a__proto__ property
  • __proto__ is actually available in some JavaScript environments
  • properties are looked up by walking through this prototype chain:
  • if an object doesn't have a property it's__proto__ is consulted

prototypal inheritance

  • modern classless pattern
  • no classes, objects inherit from objects
functionobject(parent){functionF(){}F.prototype=parent;returnnewF();}varparent={ ...}varchild=object(parent);
  • children get parent methods and properties via__proto__ link
  • parent can be created via constructor as well (not just literal)

Object.create

  • prototypal inheritance is built-in since ES5
  • Object.create(parentObject, ownPropertiesObject)

inheritance by copying properties

//shallow copyfunctionextend(parent,child){varkey;child=child||{};for(keyinparent){if(parent.hasOwnProperty(key)){child[key]=parent[key];}}returnchild;}
  • shallow copy just copies references of arrays and object
  • children can modify parent properties :(
  • deep copy is when array elements and object properties are copied as well

mixins

  • just deep copy all properties from multiple objects and mix in to a new Object
  • not like mixins in other languages, here: no link to parent

borrowing methods

  • sometimes you want to use one or two methods of an existing Objects
  • you don't want a parent-child relationship with that Object
  • can be done withcall andapply
  • pass in your object to bindthis to within the function
notMyObject.doStuff.call(myObject,param1,param2);//ornotMyObject.doStuff.apply(myObject,[param1,param2]);

example: borrowing from Array

functionexample(){return[].slice.call(arguments,1,3);//or//Array.prototype.slice.call(arguments, 1, 3)}
  • one typical example is borrowingArray methods for thearguments object

borrow and bind

  • with call/applythis reference has to be passed in when called
  • sometimes it's better to locked/bound to specific object in advance
  • bind function binds a method to an object
//simple bind functionfunctionbind(object,method){returnfunction(){returnmethod.apply(object,[].slice.call(arguments));}}

Function.prototype.bind

  • ES5 has bind builtin, it also accepts partial argument list
//basic example implementation handling partial applicationFunction.prototype.bind=Function.prototype.bind||function(thisArg){varfn=this;varslice=Array.prototype.slice;varargs=slice.call(arguments,1);returnfunction(){returnfn.call(thisArg,args.concat(slice.call(arguments)))}}

7. Design patterns

  • as made famous by the GoF book
  • language independent but mainly for Java/C++ like strongly typed languages
  • most of them are really easy to implement in JavaScript

singleton

  • only one instance of specific class
  • JS: no classes, when you create a new object there's no other like it
  • (in JS some people mean Chapter 5. module pattern by singletons)
  • you might want singletons when usingnew:
    • store instance as a (static) property on constructor function
    • but static property is public
    • can also protect instance as a private static member (via closure)
    • (be careful not to wipe out prototype properties)
varIAmSingleton;(function(){varinstance;IAmSingleton=function(){if(instance){returninstance;}instance=this;//... all the functionalitythis.whatever=true;}})();

factory

  • performs repeating operations when setting up similar objects
  • built-in Object() constructor is an example, returns Number, String, etc based in argument

other patterns

  • all easily implemented in Javascript
  • iterator - processing aggregate data
  • decorator - dinamically add functionallity to an object at runtime
  • strategy - select algorithm at runtime
  • facade - alternative interface to an object - combining method
  • proxy - alternative interface, sitting in front of object
  • mediator - separate object providing communication instead of loose coupling
  • observer - publish/subscribe to aid loose coupling, widely used in JavaScript

8. DOM and browser patterns

separation of concerns

  • content - HTML, presentation - CSS, behaviour - JS
  • progressive enhancement - basic HTML should work, too
  • no inline JS (onclick) or CSS (style attribute)
  • JS - capability detection instead of browser sniffing

DOM access

  • DOM access is expensive and should be kept to minimum
  • avoid DOM access in loops
  • assign DOM references to local variables and work with those
  • use selectors API (since IE8)
  • cache length when iterating over HTML collections (old IE versions)
  • using ids is the fastest way to access DOM elements
//var it upvarhey=document.getElementById('hey');//use selectors APIdocument.querySelector('.hello');document.querySelectorAll('.hello');

DOM manipulation

  • in addition to accessing you often want to add/remove/modify DOM elements
  • updates to DOM can be really expensive, fewer the better
  • can cause a browser to repaint the screen
  • can also cause a reflow - recalculating the elements geometry

batch DOM additions

  • do batch additon to DOM, and try doing them outside of the live tree
//create elements outside of live treevarparagraph=document.createElement('p');vartext=document.createTextNode('some text');paragraph.appendChild(text);//add it at the enddocument.body.appendChild(paragraph);
  • use a document fragment if no parent element otherwise
//create a fragment if the elements you're adding don't have a parentvarfragment=document.createDocumentFragment();fragment.appendChild(document.createElement('p'));fragment.appendChild(document.createElement('p'));//add fragment at the enddocument.body.appendChild(fragment);

batch DOM updates

  • you can make a clone of the root of the subtree you're changing
  • then swap your clone with the original
varoldNode=document.getElementById('result');varclone=oldNode.cloneNode(true);//... make your changes//then replaceoldnode.parentNode.replaceChild(clone,oldNode);

event handling

  • noonclick in HTML (seriously :)
  • usually via framework but worth knowing the basics
  • EventTarget.addEventListener(eventType, listener, useCapture) adds an event handler
  • event type - String representing event type to capture
  • listener - object implementing EventListener interface, or simply a function
  • useCapture - all events will events dispathed to this listener first before other listeners beneath this in the DOM tree
  • addEventListener is not available in IE8 and before
  • useCapture - optional (with default=false) in recent browser
  • just always pass useCapture in for broadest compatibility
  • handler is called with event object
  • e.stopPropagation() - prevents event from bubbling up to document root
  • e.preventDefault() - prevents default action (if required)

event delegation

  • events are bubbling up to parent elements
  • can reduce the number of event listeners by attaching one only to the parent
  • event properties can be used to filter out the events we care about
  • drawback: slightly more complex code but there are JS libraries to make this easy

web workers

  • javascript runs on a single thread in the browser
  • web workers: background thread support by the browser
  • only in modern browsers (from IE 10)
  • you put worker code in a separate file
  • worker can usepostMessage to send messages to the caller
  • caller can subscribe to messages usingWorker.onMessage
varworker=newWorker('my_worker.js');worker.onMessage(function(event){console.log(event.data);});//my_worker.js: postMessage('hello there');

XMLHttpRequest

  • special constructor function available in most browsers
  • allows sending HTTP requests
  • libraries wrap this - e.g. Jquery.ajax
varxhr=newXMLHttpRequest();xhr.onreadystatechange=functionhandleResponse(){if(xhr.readyState===4&&xhr.status===200){console.log(xhr.responseText);}};xhr.open('GET','page.html',true);xhr.send();

JSONP

  • JSON with padding
  • not restricted by same origin policy (but really you should just setup CORS properly)
  • callback parameter in URL specifies the JS function handling the response
  • server should return data passed into the callback function as parameter

Image beacons

  • even without javascript, data can be sent to the server
  • include an img tag (typically 1x1 transpatrent PNG)
  • actually better to respond with 204 No Content (old IE version might not like this)
  • browser makes a request when the page is being loaded

combining scripts, minification, caching

  • concatenate scripts to reduce number of HTTP requests
  • loosing some of the granular caching benefits
  • have to come up with versioning scheme
  • minify and gzip to reduce script size
  • use source maps to still allow easy debugging
  • use cache headers properly (browsers don't cache for too long by default)

script tag location and attributes

  • don't use language or type attribute as browsers assume JS anyways
  • script tags (by default) block page loading until they're downloaded, parsed and run
  • put your script tags at the bottom of the page or use HTML5 async script (since IE10)

HTTP chunking

  • sending HTTP response in chunks, browser can deal with this
  • possible to send page header first, then page content, the script tags at the bottom
  • these can be sent in different chunks, browser will progressively render

dynamic script tag example

//create script tagvarscript=document.createElement('script');script.src='my_script.js';//append to headdocument.documentElement.firstChild.appendChild(script);
  • careful with multiple files (if they depend on each other)
  • careful with what you append to (make sure it exists or use the script tag running the append)

lazy loading

  • dynamically loading (page-enhancing) JS on page onload

preloading

  • dinamically create object tag (to prevent execution)
  • set src to js file, and width, height to 0
  • next page will get that JS file from cache

About

notes for 'JavaScript Patterns' by Stoyan Stefanov

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp