SlideShare a Scribd company logo
13th September 2010
Rediscovering JavaScript
The Language BehindThe Libraries
Simon Willison, Think Vitamin JavaScript
Coming up...
✤ JavaScript, the language
✤ Object fundamentals
✤ Functions and closures
✤ Prototype inheritance
✤ JavaScript, the Libraries
✤ Event handling
✤ Animation
✤ Drag ‘n’ Drop
Let’s go back in time to 2004...
My phone
looked like this:
Nokia 7610
No one took JavaScript seriously
Well... almost no one...
“Selling the Future of DHTML”
Then, 2005 happened
May 9th, 2005 Http://www.flickr.com/photos/nataliedowne/14517351/
(me, in 2005)
Also in 2005
✤ Gmail had its first birthday, still in invite-only beta
✤ Google Maps launched February 8th
✤ The term “Ajax” was coined February 18th by Jesse James Garrett
✤ Ajaxian.com launched March 10th
A flurry of library activity
✤ February 2005: First Prototype.js
✤ March 2005: First public MochiKit code
✤ YUI started development internally at Yahoo! in 2005 (first public
release was February 2006)
✤ jQuery released at BarCamp Boston in January 2006
Different philosophical approaches
Prototype:“make JS like Ruby”
Sortable.tree(element, arguments[1]).children.map(function(item) {
return [
name + Sortable._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)
].concat(item.children.map(arguments.callee));
}).flatten().join('&');
MochiKit:“make JS like Python”
var theSum = sum(takewhile(
partial(operator.gt, 10),
imap(
partial(operator.mul, 2),
count()
)
));
YUI:“make JS like Java”
YAHOO.namespace("example.panel");
function initWait(ev) {
YAHOO.example.panel.wait = new YAHOO.widget.Panel("wait", {
width: "240px",
modal: true,
effect: {
effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5
}
});
YAHOO.example.panel.wait.beforeRenderEvent.subscribe(function() {
debug('beforeRenderEvent Fired..');
}, YAHOO.example.panel.wait, true);
YAHOO.example.panel.wait.setHeader("Loading (1), please wait...");
}
jQuery:“make JS like jQuery”
$('form#login')
.find('label.optional').hide().end()
.find('input:password').css('border', '1px solid red').end()
.submit(function(){
return confirm('Are you sure you want to submit?');
});
How can one language support so
many different programming styles?
JavaScript, the Language
Objects
Everything in JavaScript is an object
Strings and numbers
> "A string".length
8
> 123.toString()
SyntaxError: Unexpected token ILLEGAL
> (123).toString()
“123”
Even functions:
> function hello() { alert("hello") }
> hello.toString()
"function hello() { alert("hello") }"
You can make your own objects
// The same thing:
var simon = new Object();
var simon = {};
// Also the same:
simon.name = "Simon Willison"; // name is a property
simon["name"] = "Simon Willison";
// Object literal syntax is most useful:
var simon = {
name: "Simon Willison",
age: 29
};
You can loop through properties
> var simon = {
name: "Simon Willison",
age: 29
};
> for (var prop in simon) {
console.log(prop + ': ' + simon[prop]);
}
name: Simon
age: 29
(more on this later...)
(almost) Everything in JavaScript is a
property on an object
> parseInt("100 bunnies");
100
> parseInt === window.parseInt // window is the global object
true
> window === window.window
true
> window === window.window.window
true
> true === window.true
SyntaxError: Unexpected token true
Arrays
> var a = new Array(); // Old-school
> var a = []; // Literal syntax
> var a = ["dog", "cat", "chicken"];
> a.length;
3
> a[0]
"dog"
> a[2]
"chicken"
> a[3]
undefined
Iteration through arrays
> var a = ["dog", "cat", "chicken"];
> for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}
dog
cat
chicken
Tricksy array iteration
> var a = ["dog", "cat", "chicken"];
> for (var i = 0, item; item = a[i]; i++) {
console.log(item);
}
dog
cat
chicken
// But watch out for falsey values:
> var a = [123, 0, 12, 443];
> for (var i = 0, item; item = a[i]; i++) { console.log(item); }
123
Functions
Functions
Functions
// What could be simpler?
function addTwoNumbers(a, b) {
var total = a + b; // A local variable
return total;
}
> addTwoNumbers(2, 4)
6
Functions
// What could be simpler?
function addTwoNumbers(a, b) {
var total = a + b; // A local variable
return total;
}
> addTwoNumbers(2, 4)
6
> addTwoNumbers()
NaN
Functions
// What could be simpler?
function addTwoNumbers(a, b) {
var total = a + b; // A local variable
return total;
}
> addTwoNumbers(2, 4)
6
> addTwoNumbers()
NaN
> addTwoNumbers(2, 4, 8)
6
Function parameters are more
like guidelines
// arguments is a magic array-like object
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
> add(1, 3, 4, 5, 0, 5);
18
Anonymous functions
var add = function() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
var added = (function() {
var a = 2, b = 5; // Local variables
return a + b;
})();
Modern array iteration
> var a = ["dog", "cat"];
> a.forEach(function(item) {
console.log(item);
}
dog
cat
> a.forEach(function(item, index) {
console.log(index + ': ' + item);
}
0: dog
1: cat
Closures
function makeOp(op, x) {
switch(op) {
case '+':
return function(y) { return y + x };
case '-':
return function(y) { return y - x };
case '/':
return function(y) { return y / x };
case '*':
return function(y) { return y * x };
}
}
> var third = makeOp('/', 3);
> var dbl = makeOp('*', 2);
> console.log(third(12) + ' ' + dbl(8));
4 16
How does this work?
✤ Remember “everything in JavaScript is a property of an object”?
✤ Imagine that local variables belong to a “local scope” object, which
gets created when a function is executed
✤ Now imagine this object can stick around after the function has
finished executing
✤ A closure is a function plus the scope in which that function was
created
✤ Since closures capture state, you can use them as a kind of object
Real-world closure example
function revealer(el, duration) {
return function(ev) {
ev.preventDefault();
el.show(duration);
}
}
$("#mylink').click(revealer($('#panel'), 500);
$("#mylink2').click(revealer($('#panel2'), 1000);
Functions and objects
function makePerson(first, last) {
return {
"first": first,
"last": last
}
}
function personFullName(person) {
return person.first + ' ' + person.last;
}
> simon = makePerson("Simon", "Willison");
> personFullName(simon)
"Simon Willison"
First attempt at methods
function makePerson(first, last) {
return {
"first": first,
"last": last,
"fullName": function() {
return this.first + ' ' + this.last;
}
}
}
> simon = makePerson("Simon", "Willison");
> simon.fullName();
"Simon Willison"
What the heck is “this”?
✤ When you write:
> simon.fullName();
✤
fullName() is executed with this pointing to simon.
✤ If you call a method without using the '.' operator, this is set to the
global object, i.e. window.
> var fullNameMethod = simon.fullName;
> fullNameMethod();
undefined undefined
“this” is JavaScript’s magic word
You can control what this is
> simon = makePerson("Simon", "Willison");
> nat = makePerson("Natalie", "Downe");
> nat.fullName();
"Natalie Downe"
> nat.fullName.call(simon);
"Simon Willison"
> simon.fullName.apply(nat);
"Natalie Downe"
call v.s. apply
✤ Call lets you specify both the value of this and the arguments that
should be passed:
✤ myFunction.call(myThis, arg1, arg2, arg3);
✤ Apply lets you do the same thing, but pass an array of arguments
instead:
✤ myFunction.apply(myThis, [arg1, arg2, arg3]);
✤ (I always have to look this up)
Constructors
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
}
}
> var simon = new Person("Simon", "Willison");
> s.fullName();
"Simon Willison"
What does “new” do?
✤ var simon = new Person(first, last);
✤ Creates an empty object: {}
✤ Executes the Person function with this set to the new empty object
✤ Adds Person.prototype to the object's prototype chain
Prototype inheritance
The following is wasteful
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
}
}
How can we avoid creating a fullName function for every object?
Prototype inheritance
function Person(first, last) { this.first = first; this.last = last; }
Person.prototype.fullName = function() {
return this.first + ' ' + this.last;
}
> var simon = new Person("Simon", "Willison");
> simon.fullName();
"Simon Willison"
> simon.fullNameReversed();
TypeError: Object #<a Person> has no method 'fullNameReversed'
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first;
}
> simon.fullNameReversed();
"Willison, Simon"
You can extend built-in classes
> "hello".reversed();
TypeError: Object hello has no method 'reversed'
> String.prototype.reversed = function() {
var r = '';
for (var i = this.length - 1; i >= 0; i--) {
r += this[i];
}
return r;
}
> "hello".reversed();
"olleh"
That doesn’t mean you should
✤ Don’t modify objects you don’t own
✤ Extending Object.prototype breaks the (for var prop in obj) idiom
✤ Prototype.js added document.getElementsByClassName
✤ Then Mozilla added document.getElementsByClassName...
✤ The behaviour was slightly different, so code broke
✤ If you’d written your own Array.forEach() method, today your code
would be clashing with the new forEach() method in JavaScript 1.6
Prototype chain
var simon = new Person(...);
simon.toString();
Try simon.toString()
...
Try Person.prototype.toString()
...
Try Object.toString()
...
Give up
Advanced prototype chains
function Mammal() { ... }
Mammal.prototype.eatThings = ...
Person.prototype = new Mammal();
Person.prototype.learnToRead = ...
var simon = new Person(...);
simon.eatThings();
Try simon.eatThings()
...
Try Person.prototype.eatThings()
...
Try Mammal.eatThings()
...
Try Object.eatThings()
...
Give up
Let’s talk about libraries
In 2004, no one used libraries...
✤ Well, sort of...
✤ If you wanted to write anything interesting in JavaScript, there were a
few utility functions you needed in every single project
We’ll start with something easy... Events
Adding events
var link = document.getElementById(‘mylink’);
link.onclick = function() {
alert(this.href);
return false;
}
Adding more than one event?
// W3C standard browsers
var link = document.getElementById('mylink');
link.addEventListener('click', function() {
alert("Hello");
return false;
});
// IE 6
link.attachEvent("onclick", function() {
alert("Hello");
return false;
);
The addEvent function
function addEvent(obj, evType, fn, useCapture){
  if (obj.addEventListener){
    obj.addEventListener(evType, fn, useCapture);
    return true;
  } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be attached");
  }
}
// DON'T USE THIS THOUGH
http://www.scottandrew.com/weblog/articles/cbs-events
✤ What if you want to keep track of the event listeners that have been
added?
✤ In particular so you can manually de-register them when the page
unloads, to clean up potential memory leaks in IE
✤ addEvent doesn't fix the different event objects for you, so you still
have to work around browser differences there
addEvent drawbacks
Dean Edwards addEvent
function addEvent(element, type, handler) {
" if (element.addEventListener) {
" " element.addEventListener(type, handler, false);
" } else {
" " // assign each event handler a unique ID
" " if (!handler.$$guid) handler.$$guid = addEvent.guid++;
" " // create a hash table of event types for the element
" " if (!element.events) element.events = {};
" " // create a hash table of event handlers for each element/event pair
" " var handlers = element.events[type];
" " if (!handlers) {
" " " handlers = element.events[type] = {};
" " " // store the existing event handler (if there is one)
" " " if (element["on" + type]) {
" " " " handlers[0] = element["on" + type];
" " " }
" " }
" " // store the event handler in the hash table
" " handlers[handler.$$guid] = handler;
" " // assign a global event handler to do all the work
" " element["on" + type] = handleEvent;
" }
};
// a counter used to create unique IDs
addEvent.guid = 1;
Dean Edwards addEvent (2)
function removeEvent(element, type, handler) {
" if (element.removeEventListener) {
" " element.removeEventListener(type, handler, false);
" } else {
" " // delete the event handler from the hash table
" " if (element.events && element.events[type]) {
" " " delete element.events[type][handler.$$guid];
" " }
" }
};
function handleEvent(event) {
" var returnValue = true;
" // grab the event object (IE uses a global event object)
" event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
" // get a reference to the hash table of event handlers
" var handlers = this.events[event.type];
" // execute each event handler
" for (var i in handlers) {
" " this.$$handleEvent = handlers[i];
" " if (this.$$handleEvent(event) === false) {
" " " returnValue = false;
" " }
" }
" return returnValue;
};
Dean Edwards addEvent (3)
function fixEvent(event) {
" // add W3C standard event methods
" event.preventDefault = fixEvent.preventDefault;
" event.stopPropagation = fixEvent.stopPropagation;
" return event;
};
fixEvent.preventDefault = function() {
" this.returnValue = false;
};
fixEvent.stopPropagation = function() {
" this.cancelBubble = true;
};
Want to know where the mouse is?
addEvent(div, 'mouseover', function(ev) {
" if (!ev) var ev = window.event; // For IE
" var posx = 0;
" var posy = 0;
" if (ev.pageX || ev.pageY) {
" " posx = ev.pageX;
" " posy = ev.pageY;
" } else if (e.clientX || e.clientY) {
" " posx = e.clientX + document.body.scrollLeft
" " " + document.documentElement.scrollLeft;
" " posy = e.clientY + document.body.scrollTop
" " " + document.documentElement.scrollTop;
" }
});
// http://www.quirksmode.org/js/events_properties.html
http://www.quirksmode.org/js/ for more
How about animation?
Animate a div moving across a screen
✤ Easy! Just use setInterval() to move it left 10 pixels every 10th of a
second
✤ But... what if you're animating lots of things, and the user's
computer can't keep up...
✤ Solution: figure out where you want it to be in 2 seconds time, then
check how much time has elapsed each time round the animation
loop and adjust the position accordingly
Drag and Drop?
✤ Watch out for an onmousedown event over the object you want to
drag
✤ Attach an onmousemove event to the body, and move the element
with the mouse
✤ Watch for onmouseup, and remove the mousemove handler
✤ Simple right?
Drag and drop implementation
Drag and drop, for real
✤ Need to be able to distinguish between a click and a drag
✤ How about... a drag starts when
✤ The user moves their mouse at least 5 pixels
✤ OR... the user holds down the mose button on the draggable for at
least a full second
✤ Need to restrict the area in which the draggable can be dragged
✤
Highlight drop targets when the draggable intersects them
✤ Revert the position of the item if it’s dropped in the wrong place...
http://developer.yahoo.com/ypatterns/richinteraction/dragdrop/modules.html
The truth is...
✤ By the time you’ve implemented event handling, basic animation,
DOM manipulation and drag and drop, you’ve re-invented a sizable
chunk of jQuery, YUI or Dojo, probably with more lines of code and
definitely with a whole lot more bugs.
So how does jQuery do it?
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
A simple example
jQuery(function($) {
var div = $('#sessions-placeholder');
$('ul.tags a').click(function(ev) {
ev.preventDefault();
var a = $(this);
div.html(
'<img src="/static/img/loaders/ajax-loader-blue.gif" ' +
'style="margin-bottom: 1em" />'
);
div.load(a.attr('href') + '?ajax=1');
a.closest('ul').find('li').removeClass('selected');
a.closest('li').addClass('selected');
});
});
Moral:
Learn JavaScript properly, but
don’t write your own library
unless you’re a total glutton for
punishment
http://lanyrd.com/scch

More Related Content

PDF
Crowdsourcing with Django
PDF
Coffeescript a z
PDF
Prototype & jQuery
PDF
PhoneGap: Local Storage
ODP
Introduction to jQuery
PDF
jQuery Essentials
PDF
Learning jQuery in 30 minutes
KEY
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1
Crowdsourcing with Django
Coffeescript a z
Prototype & jQuery
PhoneGap: Local Storage
Introduction to jQuery
jQuery Essentials
Learning jQuery in 30 minutes
Building Single Page Apps with Backbone.js, Coffeescript and Rails 3.1

What's hot (20)

PDF
History of jQuery
PDF
Jquery In Rails
PDF
Idioms in swift 2016 05c
PDF
Jqeury ajax plugins
PDF
HTML5 and CSS3 Refresher
PPT
A Short Introduction To jQuery
KEY
Desarrollando aplicaciones web en minutos
PDF
Introduction to ECMAScript 2015
PPTX
Taming that client side mess with Backbone.js
PPTX
jQuery Data Manipulate API - A source code dissecting journey
PDF
DataMapper @ RubyEnRails2009
PDF
Юрий Буянов «Squeryl — ORM с человеческим лицом»
PPT
JQuery Flot
KEY
Datamapper @ Railsconf2010
PPT
Jquery Best Practices
PDF
Node.js - Demnächst auf einem Server in Ihrer Nähe
PDF
Modern Application Foundations: Underscore and Twitter Bootstrap
ODP
Drupal Best Practices
PDF
The Beauty of Java Script
PDF
Closure, Higher-order function in Swift
History of jQuery
Jquery In Rails
Idioms in swift 2016 05c
Jqeury ajax plugins
HTML5 and CSS3 Refresher
A Short Introduction To jQuery
Desarrollando aplicaciones web en minutos
Introduction to ECMAScript 2015
Taming that client side mess with Backbone.js
jQuery Data Manipulate API - A source code dissecting journey
DataMapper @ RubyEnRails2009
Юрий Буянов «Squeryl — ORM с человеческим лицом»
JQuery Flot
Datamapper @ Railsconf2010
Jquery Best Practices
Node.js - Demnächst auf einem Server in Ihrer Nähe
Modern Application Foundations: Underscore and Twitter Bootstrap
Drupal Best Practices
The Beauty of Java Script
Closure, Higher-order function in Swift
Ad

Viewers also liked (6)

PDF
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
PDF
Good Parts of JavaScript Douglas Crockford
PPT
Advanced Javascript
PDF
The JavaScript Programming Language
PDF
Javascript Best Practices
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Good Parts of JavaScript Douglas Crockford
Advanced Javascript
The JavaScript Programming Language
Javascript Best Practices
Ad

Similar to Rediscovering JavaScript: The Language Behind The Libraries (20)

PDF
Intro to Advanced JavaScript
PDF
Introduction kot iin
PDF
JavaScript Survival Guide
KEY
Javascript tid-bits
PPTX
Getting classy with ES6
PPTX
ES6: Features + Rails
PPTX
Elegant objects
DOC
Jsphp 110312161301-phpapp02
PDF
ES6 generators
PDF
JavaScript - Like a Box of Chocolates
PPTX
Everyday's JS
PDF
Realm: Building a mobile database
PPTX
Ian 20150116 java script oop
PDF
Say It With Javascript
PPTX
Swift - Modern & Expressive, or Magical Unicorn?
PPTX
Maintainable JavaScript 2012
PDF
The Beauty Of Java Script V5a
PDF
JavaScript for PHP developers
PPTX
JavaScript Objects and OOP Programming with JavaScript
PDF
JavaScript patterns
Intro to Advanced JavaScript
Introduction kot iin
JavaScript Survival Guide
Javascript tid-bits
Getting classy with ES6
ES6: Features + Rails
Elegant objects
Jsphp 110312161301-phpapp02
ES6 generators
JavaScript - Like a Box of Chocolates
Everyday's JS
Realm: Building a mobile database
Ian 20150116 java script oop
Say It With Javascript
Swift - Modern & Expressive, or Magical Unicorn?
Maintainable JavaScript 2012
The Beauty Of Java Script V5a
JavaScript for PHP developers
JavaScript Objects and OOP Programming with JavaScript
JavaScript patterns

More from Simon Willison (20)

PDF
How Lanyrd does Geo
PDF
Cheap tricks for startups
PDF
The Django Web Framework (EuroPython 2006)
PDF
Building Lanyrd
PDF
How we bootstrapped Lanyrd using Twitter's social graph
PDF
Web Services for Fun and Profit
PDF
Tricks & challenges developing a large Django application
PDF
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
PDF
How Lanyrd uses Twitter
PDF
ScaleFail
PDF
Building Things Fast - and getting approval
PDF
Building crowdsourcing applications
PDF
Evented I/O based web servers, explained using bunnies
PDF
Cowboy development with Django
PDF
Django Heresies
PDF
Class-based views with Django
PDF
Web App Security Horror Stories
PDF
Web Security Horror Stories
PDF
When Zeppelins Ruled The Earth
PDF
When Ajax Attacks! Web application security fundamentals
How Lanyrd does Geo
Cheap tricks for startups
The Django Web Framework (EuroPython 2006)
Building Lanyrd
How we bootstrapped Lanyrd using Twitter's social graph
Web Services for Fun and Profit
Tricks & challenges developing a large Django application
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
How Lanyrd uses Twitter
ScaleFail
Building Things Fast - and getting approval
Building crowdsourcing applications
Evented I/O based web servers, explained using bunnies
Cowboy development with Django
Django Heresies
Class-based views with Django
Web App Security Horror Stories
Web Security Horror Stories
When Zeppelins Ruled The Earth
When Ajax Attacks! Web application security fundamentals

Recently uploaded (20)

PDF
A comparative analysis of optical character recognition models for extracting...
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
Cloud computing and distributed systems.
PDF
cuic standard and advanced reporting.pdf
PPT
Teaching material agriculture food technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Empathic Computing: Creating Shared Understanding
PPTX
Machine Learning_overview_presentation.pptx
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
A comparative analysis of optical character recognition models for extracting...
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Spectral efficient network and resource selection model in 5G networks
Programs and apps: productivity, graphics, security and other tools
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Cloud computing and distributed systems.
cuic standard and advanced reporting.pdf
Teaching material agriculture food technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Empathic Computing: Creating Shared Understanding
Machine Learning_overview_presentation.pptx
Dropbox Q2 2025 Financial Results & Investor Presentation
“AI and Expert System Decision Support & Business Intelligence Systems”
The Rise and Fall of 3GPP – Time for a Sabbatical?
Network Security Unit 5.pdf for BCA BBA.
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx

Rediscovering JavaScript: The Language Behind The Libraries

  • 1. 13th September 2010 Rediscovering JavaScript The Language BehindThe Libraries Simon Willison, Think Vitamin JavaScript
  • 2. Coming up... ✤ JavaScript, the language ✤ Object fundamentals ✤ Functions and closures ✤ Prototype inheritance ✤ JavaScript, the Libraries ✤ Event handling ✤ Animation ✤ Drag ‘n’ Drop
  • 3. Let’s go back in time to 2004...
  • 4. My phone looked like this: Nokia 7610
  • 5. No one took JavaScript seriously
  • 7. “Selling the Future of DHTML”
  • 9. May 9th, 2005 Http://www.flickr.com/photos/nataliedowne/14517351/ (me, in 2005)
  • 10. Also in 2005 ✤ Gmail had its first birthday, still in invite-only beta ✤ Google Maps launched February 8th ✤ The term “Ajax” was coined February 18th by Jesse James Garrett ✤ Ajaxian.com launched March 10th
  • 11. A flurry of library activity ✤ February 2005: First Prototype.js ✤ March 2005: First public MochiKit code ✤ YUI started development internally at Yahoo! in 2005 (first public release was February 2006) ✤ jQuery released at BarCamp Boston in January 2006
  • 13. Prototype:“make JS like Ruby” Sortable.tree(element, arguments[1]).children.map(function(item) { return [ name + Sortable._constructIndex(item) + "[id]=" + encodeURIComponent(item.id) ].concat(item.children.map(arguments.callee)); }).flatten().join('&');
  • 14. MochiKit:“make JS like Python” var theSum = sum(takewhile( partial(operator.gt, 10), imap( partial(operator.mul, 2), count() ) ));
  • 15. YUI:“make JS like Java” YAHOO.namespace("example.panel"); function initWait(ev) { YAHOO.example.panel.wait = new YAHOO.widget.Panel("wait", { width: "240px", modal: true, effect: { effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5 } }); YAHOO.example.panel.wait.beforeRenderEvent.subscribe(function() { debug('beforeRenderEvent Fired..'); }, YAHOO.example.panel.wait, true); YAHOO.example.panel.wait.setHeader("Loading (1), please wait..."); }
  • 16. jQuery:“make JS like jQuery” $('form#login') .find('label.optional').hide().end() .find('input:password').css('border', '1px solid red').end() .submit(function(){ return confirm('Are you sure you want to submit?'); });
  • 17. How can one language support so many different programming styles?
  • 20. Everything in JavaScript is an object Strings and numbers > "A string".length 8 > 123.toString() SyntaxError: Unexpected token ILLEGAL > (123).toString() “123” Even functions: > function hello() { alert("hello") } > hello.toString() "function hello() { alert("hello") }"
  • 21. You can make your own objects // The same thing: var simon = new Object(); var simon = {}; // Also the same: simon.name = "Simon Willison"; // name is a property simon["name"] = "Simon Willison"; // Object literal syntax is most useful: var simon = { name: "Simon Willison", age: 29 };
  • 22. You can loop through properties > var simon = { name: "Simon Willison", age: 29 }; > for (var prop in simon) { console.log(prop + ': ' + simon[prop]); } name: Simon age: 29 (more on this later...)
  • 23. (almost) Everything in JavaScript is a property on an object > parseInt("100 bunnies"); 100 > parseInt === window.parseInt // window is the global object true > window === window.window true > window === window.window.window true > true === window.true SyntaxError: Unexpected token true
  • 24. Arrays > var a = new Array(); // Old-school > var a = []; // Literal syntax > var a = ["dog", "cat", "chicken"]; > a.length; 3 > a[0] "dog" > a[2] "chicken" > a[3] undefined
  • 25. Iteration through arrays > var a = ["dog", "cat", "chicken"]; > for (var i = 0; i < a.length; i++) { console.log(a[i]); } dog cat chicken
  • 26. Tricksy array iteration > var a = ["dog", "cat", "chicken"]; > for (var i = 0, item; item = a[i]; i++) { console.log(item); } dog cat chicken // But watch out for falsey values: > var a = [123, 0, 12, 443]; > for (var i = 0, item; item = a[i]; i++) { console.log(item); } 123
  • 29. Functions // What could be simpler? function addTwoNumbers(a, b) { var total = a + b; // A local variable return total; } > addTwoNumbers(2, 4) 6
  • 30. Functions // What could be simpler? function addTwoNumbers(a, b) { var total = a + b; // A local variable return total; } > addTwoNumbers(2, 4) 6 > addTwoNumbers() NaN
  • 31. Functions // What could be simpler? function addTwoNumbers(a, b) { var total = a + b; // A local variable return total; } > addTwoNumbers(2, 4) 6 > addTwoNumbers() NaN > addTwoNumbers(2, 4, 8) 6
  • 32. Function parameters are more like guidelines // arguments is a magic array-like object function add() { var sum = 0; for (var i = 0, j = arguments.length; i < j; i++) { sum += arguments[i]; } return sum; } > add(1, 3, 4, 5, 0, 5); 18
  • 33. Anonymous functions var add = function() { var sum = 0; for (var i = 0, j = arguments.length; i < j; i++) { sum += arguments[i]; } return sum; } var added = (function() { var a = 2, b = 5; // Local variables return a + b; })();
  • 34. Modern array iteration > var a = ["dog", "cat"]; > a.forEach(function(item) { console.log(item); } dog cat > a.forEach(function(item, index) { console.log(index + ': ' + item); } 0: dog 1: cat
  • 35. Closures function makeOp(op, x) { switch(op) { case '+': return function(y) { return y + x }; case '-': return function(y) { return y - x }; case '/': return function(y) { return y / x }; case '*': return function(y) { return y * x }; } } > var third = makeOp('/', 3); > var dbl = makeOp('*', 2); > console.log(third(12) + ' ' + dbl(8)); 4 16
  • 36. How does this work? ✤ Remember “everything in JavaScript is a property of an object”? ✤ Imagine that local variables belong to a “local scope” object, which gets created when a function is executed ✤ Now imagine this object can stick around after the function has finished executing ✤ A closure is a function plus the scope in which that function was created ✤ Since closures capture state, you can use them as a kind of object
  • 37. Real-world closure example function revealer(el, duration) { return function(ev) { ev.preventDefault(); el.show(duration); } } $("#mylink').click(revealer($('#panel'), 500); $("#mylink2').click(revealer($('#panel2'), 1000);
  • 38. Functions and objects function makePerson(first, last) { return { "first": first, "last": last } } function personFullName(person) { return person.first + ' ' + person.last; } > simon = makePerson("Simon", "Willison"); > personFullName(simon) "Simon Willison"
  • 39. First attempt at methods function makePerson(first, last) { return { "first": first, "last": last, "fullName": function() { return this.first + ' ' + this.last; } } } > simon = makePerson("Simon", "Willison"); > simon.fullName(); "Simon Willison"
  • 40. What the heck is “this”? ✤ When you write: > simon.fullName(); ✤ fullName() is executed with this pointing to simon. ✤ If you call a method without using the '.' operator, this is set to the global object, i.e. window. > var fullNameMethod = simon.fullName; > fullNameMethod(); undefined undefined
  • 42. You can control what this is > simon = makePerson("Simon", "Willison"); > nat = makePerson("Natalie", "Downe"); > nat.fullName(); "Natalie Downe" > nat.fullName.call(simon); "Simon Willison" > simon.fullName.apply(nat); "Natalie Downe"
  • 43. call v.s. apply ✤ Call lets you specify both the value of this and the arguments that should be passed: ✤ myFunction.call(myThis, arg1, arg2, arg3); ✤ Apply lets you do the same thing, but pass an array of arguments instead: ✤ myFunction.apply(myThis, [arg1, arg2, arg3]); ✤ (I always have to look this up)
  • 44. Constructors function Person(first, last) { this.first = first; this.last = last; this.fullName = function() { return this.first + ' ' + this.last; } } > var simon = new Person("Simon", "Willison"); > s.fullName(); "Simon Willison"
  • 45. What does “new” do? ✤ var simon = new Person(first, last); ✤ Creates an empty object: {} ✤ Executes the Person function with this set to the new empty object ✤ Adds Person.prototype to the object's prototype chain
  • 46. Prototype inheritance The following is wasteful function Person(first, last) { this.first = first; this.last = last; this.fullName = function() { return this.first + ' ' + this.last; } } How can we avoid creating a fullName function for every object?
  • 47. Prototype inheritance function Person(first, last) { this.first = first; this.last = last; } Person.prototype.fullName = function() { return this.first + ' ' + this.last; } > var simon = new Person("Simon", "Willison"); > simon.fullName(); "Simon Willison" > simon.fullNameReversed(); TypeError: Object #<a Person> has no method 'fullNameReversed' Person.prototype.fullNameReversed = function() { return this.last + ', ' + this.first; } > simon.fullNameReversed(); "Willison, Simon"
  • 48. You can extend built-in classes > "hello".reversed(); TypeError: Object hello has no method 'reversed' > String.prototype.reversed = function() { var r = ''; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; } > "hello".reversed(); "olleh"
  • 49. That doesn’t mean you should ✤ Don’t modify objects you don’t own ✤ Extending Object.prototype breaks the (for var prop in obj) idiom ✤ Prototype.js added document.getElementsByClassName ✤ Then Mozilla added document.getElementsByClassName... ✤ The behaviour was slightly different, so code broke ✤ If you’d written your own Array.forEach() method, today your code would be clashing with the new forEach() method in JavaScript 1.6
  • 50. Prototype chain var simon = new Person(...); simon.toString(); Try simon.toString() ... Try Person.prototype.toString() ... Try Object.toString() ... Give up
  • 51. Advanced prototype chains function Mammal() { ... } Mammal.prototype.eatThings = ... Person.prototype = new Mammal(); Person.prototype.learnToRead = ... var simon = new Person(...); simon.eatThings(); Try simon.eatThings() ... Try Person.prototype.eatThings() ... Try Mammal.eatThings() ... Try Object.eatThings() ... Give up
  • 52. Let’s talk about libraries
  • 53. In 2004, no one used libraries... ✤ Well, sort of... ✤ If you wanted to write anything interesting in JavaScript, there were a few utility functions you needed in every single project
  • 54. We’ll start with something easy... Events
  • 55. Adding events var link = document.getElementById(‘mylink’); link.onclick = function() { alert(this.href); return false; }
  • 56. Adding more than one event? // W3C standard browsers var link = document.getElementById('mylink'); link.addEventListener('click', function() { alert("Hello"); return false; }); // IE 6 link.attachEvent("onclick", function() { alert("Hello"); return false; );
  • 57. The addEvent function function addEvent(obj, evType, fn, useCapture){   if (obj.addEventListener){     obj.addEventListener(evType, fn, useCapture);     return true;   } else if (obj.attachEvent){     var r = obj.attachEvent("on"+evType, fn);     return r;   } else {     alert("Handler could not be attached");   } } // DON'T USE THIS THOUGH http://www.scottandrew.com/weblog/articles/cbs-events
  • 58. ✤ What if you want to keep track of the event listeners that have been added? ✤ In particular so you can manually de-register them when the page unloads, to clean up potential memory leaks in IE ✤ addEvent doesn't fix the different event objects for you, so you still have to work around browser differences there addEvent drawbacks
  • 59. Dean Edwards addEvent function addEvent(element, type, handler) { " if (element.addEventListener) { " " element.addEventListener(type, handler, false); " } else { " " // assign each event handler a unique ID " " if (!handler.$$guid) handler.$$guid = addEvent.guid++; " " // create a hash table of event types for the element " " if (!element.events) element.events = {}; " " // create a hash table of event handlers for each element/event pair " " var handlers = element.events[type]; " " if (!handlers) { " " " handlers = element.events[type] = {}; " " " // store the existing event handler (if there is one) " " " if (element["on" + type]) { " " " " handlers[0] = element["on" + type]; " " " } " " } " " // store the event handler in the hash table " " handlers[handler.$$guid] = handler; " " // assign a global event handler to do all the work " " element["on" + type] = handleEvent; " } }; // a counter used to create unique IDs addEvent.guid = 1;
  • 60. Dean Edwards addEvent (2) function removeEvent(element, type, handler) { " if (element.removeEventListener) { " " element.removeEventListener(type, handler, false); " } else { " " // delete the event handler from the hash table " " if (element.events && element.events[type]) { " " " delete element.events[type][handler.$$guid]; " " } " } }; function handleEvent(event) { " var returnValue = true; " // grab the event object (IE uses a global event object) " event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); " // get a reference to the hash table of event handlers " var handlers = this.events[event.type]; " // execute each event handler " for (var i in handlers) { " " this.$$handleEvent = handlers[i]; " " if (this.$$handleEvent(event) === false) { " " " returnValue = false; " " } " } " return returnValue; };
  • 61. Dean Edwards addEvent (3) function fixEvent(event) { " // add W3C standard event methods " event.preventDefault = fixEvent.preventDefault; " event.stopPropagation = fixEvent.stopPropagation; " return event; }; fixEvent.preventDefault = function() { " this.returnValue = false; }; fixEvent.stopPropagation = function() { " this.cancelBubble = true; };
  • 62. Want to know where the mouse is? addEvent(div, 'mouseover', function(ev) { " if (!ev) var ev = window.event; // For IE " var posx = 0; " var posy = 0; " if (ev.pageX || ev.pageY) { " " posx = ev.pageX; " " posy = ev.pageY; " } else if (e.clientX || e.clientY) { " " posx = e.clientX + document.body.scrollLeft " " " + document.documentElement.scrollLeft; " " posy = e.clientY + document.body.scrollTop " " " + document.documentElement.scrollTop; " } }); // http://www.quirksmode.org/js/events_properties.html
  • 65. Animate a div moving across a screen ✤ Easy! Just use setInterval() to move it left 10 pixels every 10th of a second ✤ But... what if you're animating lots of things, and the user's computer can't keep up... ✤ Solution: figure out where you want it to be in 2 seconds time, then check how much time has elapsed each time round the animation loop and adjust the position accordingly
  • 67. ✤ Watch out for an onmousedown event over the object you want to drag ✤ Attach an onmousemove event to the body, and move the element with the mouse ✤ Watch for onmouseup, and remove the mousemove handler ✤ Simple right? Drag and drop implementation
  • 68. Drag and drop, for real ✤ Need to be able to distinguish between a click and a drag ✤ How about... a drag starts when ✤ The user moves their mouse at least 5 pixels ✤ OR... the user holds down the mose button on the draggable for at least a full second ✤ Need to restrict the area in which the draggable can be dragged ✤ Highlight drop targets when the draggable intersects them ✤ Revert the position of the item if it’s dropped in the wrong place...
  • 70. The truth is... ✤ By the time you’ve implemented event handling, basic animation, DOM manipulation and drag and drop, you’ve re-invented a sizable chunk of jQuery, YUI or Dojo, probably with more lines of code and definitely with a whole lot more bugs.
  • 71. So how does jQuery do it?
  • 72. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 73. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 74. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 75. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 76. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 77. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 78. A simple example jQuery(function($) { var div = $('#sessions-placeholder'); $('ul.tags a').click(function(ev) { ev.preventDefault(); var a = $(this); div.html( '<img src="/static/img/loaders/ajax-loader-blue.gif" ' + 'style="margin-bottom: 1em" />' ); div.load(a.attr('href') + '?ajax=1'); a.closest('ul').find('li').removeClass('selected'); a.closest('li').addClass('selected'); }); });
  • 79. Moral: Learn JavaScript properly, but don’t write your own library unless you’re a total glutton for punishment