SlideShare a Scribd company logo
Clean JavaScript


http://www.flickr.com/photos/hoshikowolrd/5151171470/




                                                         Sapporo.js
SaCSS vol.29 - 2011.11.26                              (Ryunosuke SATO)
Community for people who like JavaScript.




      Sapporo.js
Sapporo.js




http://sapporojs.org
Sapporo.js




Now learning
Clean Javascript
I’m a programmer
@tricknotes
Clean Javascript
Clean JavaScript


http://www.flickr.com/photos/hoshikowolrd/5151171470/




                                                         Sapporo.js
SaCSS vol.29 - 2011.11.26                              (Ryunosuke SATO)
Clean Javascript
Clean Javascript
Clean Javascript
Clean Javascript
Clean Javascript
Clean Javascript
Clean Javascript
JavaScript
JavaScript
about JavaScript
Works in everywhere!
http://www.flickr.com/photos/peco-sunnyday/2752403413/




                interesting!
I like
JavaScript is most popular!
but...
http://www.flickr.com/photos/maynard/6105929170/




                              difficult
Now training...
?
                     ?
How to face the difficulty
Clean Javascript
Clean Javascript
Oops... :(
some ideas
with

DOM
point
HTML   JavaScript
HTML   JavaScript
here!




HTML       JavaScript
practice
- Attach events from outer -

problem


   JavaScript
- Attach events from outer -

solution


HTML
 JavaScript
- Attach events from outer -




<a onclick=”showMessage()”>Click me</a>




                                    code smell
- Attach events from outer -




<a id=”showMessage”>Click me</a>


var a = document.getElementById(‘showMessage’);
a.addEventListener(‘click’, showMessage);



                                       improvement
- Separate from Selector -

problem


HTML   id   class
- Separate from Selector -

solution



HTML   id   class
- Separate from Selector -




function showPhoto(photoId) {
  var photo = document.getElementById(‘photo-’ + photoId);
  // do ...
}
- Separate from Selector -




function showPhoto(photoId) {
  var photo = document.getElementById(‘photo-’ + photoId);
  // do ...
}




                                              code smell
- Separate from Selector -


var showPhoto = function(element) {
  // do ...
}

var photo = document.getElementById(‘photo-12’);
showPhoto(photo);




                                      improvement
- modulized functions -

problem
- modulized functions -

solution
- modulized functions -

// users.js
var showUserName = function() {
  // do somethig
}

var showUserAge = function(){
  // do somethig
}

var validateUserForm = function() {
  // do somethig
}                                   code smell
- modulized functions -

// users.js
var showUserName = function() {
  // do somethig
}                             global

var showUserAge = function(){
  // do somethig
}

var validateUserForm = function() {
  // do somethig
}
- modulized functions -
// users.js
var users = {};
                               global
users.showName = function () {
  // do somethig
}

users.showAge = function (){
  // do somethig
}

users.validateForm = function () {
  // do somethig
}
- modulized functions -
// users.js
(function(global) {
  global.users = {};            global

 users.showName = function () {
   // do somethig
 }

  // ...
)(this);


                                    improvement
overwrite behavior -

problem


     JavaScript
 DOM
overwrite behavior -
solution


 DOM
           DOM
overwrite behavior -

// using jQuery

$(‘a#showDialog’).click(function() {
  $.ajax(‘/about’, {
    success: function(html) {
      // do something...
    }
  });
});




                                       code smell
overwrite behavior -

// using jQuery

$(‘a#showDialog’).click(function() {
  $.ajax($(this).attr(‘href’), {
    success: function(html) {
      // do something...
    }
  });
});




                                   improvement
shallow scope -

problem
shallow scope -

solution


        2            function


    →         this
shallow scope -


// using jQuery

var $elements = $(‘a#remote’);
$elements.click(function() {
  var url = $(this).attr(‘href’);
  $.ajax(url, {
    success: function(html) {
      var text = $(html).text();
      $element.text(text);
    }
  });
  return false;
});
shallow scope -


// using jQuery

var $elements = $(‘a#remote’);
$elements.click(function() {         deep
  var url = $(this).attr(‘href’);
  $.ajax(url, {
    success: function(html) {
      var text = $(html).text();
      $element.text(text);
    }
  });
  return false;
});

                                            code smell
shallow scope -


// using jQuery

var $elements = $(‘a#remote’);
$elements.click(function() {
  var url = $(this).attr(‘href’);
  $.ajax(url, {
    success: function(html) {
       var text = $(html).text();
       $(this).text(text);
    },
    context: this
  });
  return false;
});
                                           improvement
DOM       - DOM to model -

problem


DOM
DOM        - DOM to model -

solution


DOM
DOM                                     - DOM to model -


var element = document.getElementById(‘message’);
element.addEventListener(‘click’, function() {
  // this == element
  if (this.getAttribute(‘data-is-checked’)) {
    this.setAttribute(‘data-is-checked’, true);
    this.innerText = ‘clicked!’;
  }
});




                                                code smell
DOM                                                        - DOM to model -


var domToModel = function(element, Model) {
  var method, name, object, parent, proto;
  model = Object.create(element);
  proto = Model.prototype;
  for (name in proto) {
    method = proto[name];
    model[name] = method;
  }
  Model.apply(model);
  return model;
};

var CustomElement = function() {};
CustomElement.prototype.showText = function() {
   if (!this.getAttribute(‘data-is-checked’)) {   var element = document.getElementById(‘message’);
    this.setAttribute(‘data-is-checked’, true);   var model = domToModel(element, CustomElement);
    this.innerText = ‘clicked!’;                  model.addEventListener(‘click’, function() {
  }                                                 model.showText();
};                                                });
DOM                                                        - DOM to model -


var domToModel = function(element, Model) {
  var method, name, object, parent, proto;
  model = Object.create(element);
  proto = Model.prototype;
  for (name in proto) {
    method = proto[name];
    model[name] = method;
  }
  Model.apply(model);
  return model;
};

var CustomElement = function() {};
CustomElement.prototype.showText = function() {
   if (!this.getAttribute(‘data-is-checked’)) {   var element = document.getElementById(‘message’);
    this.setAttribute(‘data-is-checked’, true);   var model = domToModel(element, CustomElement);
    this.innerText = ‘clicked!’;                  model.addEventListener(‘click’, function() {
  }                                                 model.showText();
};                                                });
DOM                                                        - DOM to model -


var domToModel = function(element, Model) {
  var method, name, object, parent, proto;
  model = Object.create(element);
  proto = Model.prototype;
  for (name in proto) {
    method = proto[name];
    model[name] = method;
  }
  Model.apply(model);
  return model;
};

var CustomElement = function() {};
CustomElement.prototype.showText = function() {
   if (!this.getAttribute(‘data-is-checked’)) {   var element = document.getElementById(‘message’);
    this.setAttribute(‘data-is-checked’, true);   var model = domToModel(element, CustomElement);
    this.innerText = ‘clicked!’;                  model.addEventListener(‘click’, function() {
  }                                                 model.showText();
};                                                });

                                                                   improvement
- separate logic with view -

problem
- separate logic with view -
solution
- separate logic with view -

function createTimer() {
  var timerId;
  var startTimer = function(millisec) {
    timerId = setTimeout(function() {
      $(‘.timeout’).text(‘finished’);
    }, millisec);
  }
  var stopTimer = function() {
    clearTimeout(timerId);
  }
  return {
    startTimer: startTimer,
    stopTimer: stopTimer
  }
}
- separate logic with view -

function createTimer() {
  var timerId;
  var startTimer = function(millisec) {
    timerId = setTimeout(function() {
      $(‘.timeout’).text(‘finished’);      view
    }, millisec);
  }
  var stopTimer = function() {
    clearTimeout(timerId);
  }
  return {
    startTimer: startTimer,
    stopTimer: stopTimer
  }
}
                                                   code smell
- separate logic with view -
function Timer(millisec) {
  this. millisec = millisec;
  this.callbacks = [];
  this.timerId = null;
}

Timer.prototype.afterFinish = function(callback) {
  return this.callbacks.push(callback);
};

Timer.prototype.start = function() {
  var callbacks = this.callbacks;
  this.timerId = setTimeout(function() {
    var callback, i, length;
    for (i = 0, length = callbacks.length; i < length; i++) {   var timer = new Timer(1000);
      callback = callbacks[i];                                  timer.afterFinish(function() {
      callback();                                                 $('.timer .message').text('Finished!!');
    }                                                           });
  }, this. millisec);                                           timer.start();
};

Timer.prototype.stop = function() {
  clearTimeout(this.timerId);
}
- separate logic with view -
function Timer(millisec) {
  this. millisec = millisec;
  this.callbacks = [];

}
  this.timerId = null;
                                                                  model
Timer.prototype.afterFinish = function(callback) {
  return this.callbacks.push(callback);
};

Timer.prototype.start = function() {                                      view
  var callbacks = this.callbacks;
  this.timerId = setTimeout(function() {
    var callback, i, length;
    for (i = 0, length = callbacks.length; i < length; i++) {   var timer = new Timer(1000);
      callback = callbacks[i];                                  timer.afterFinish(function() {
      callback();                                                 $('.timer .message').text('Finished!!');
    }                                                           });
  }, this. millisec);                                           timer.start();
};

Timer.prototype.stop = function() {
  clearTimeout(this.timerId);
}                                                                      improvement
A tiny fraction
Clean Javascript
others...
Pure JavaScript
Clean Javascript
Application
https://gist.github.com/1362110
http://documentcloud.github.com/backbone/
http://www.sproutcore.com/
Clean Javascript
interest




http://www.flickr.com/photos/bonguri/4610536789/
reading
Good text
writing
Clean Javascript
Shall we learn
      about
Clean JavaScript?

More Related Content

PDF
Testable JavaScript
PDF
React
KEY
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
PDF
React 소개 및 구현방법 Demo
PDF
Building a Startup Stack with AngularJS
PDF
Javascript Module Patterns
PPTX
Backbone.js
PPTX
Django + Vue, JavaScript de 3ª generación para modernizar Django
Testable JavaScript
React
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
React 소개 및 구현방법 Demo
Building a Startup Stack with AngularJS
Javascript Module Patterns
Backbone.js
Django + Vue, JavaScript de 3ª generación para modernizar Django

What's hot (20)

PDF
Backbone.js
PDF
Integrating Angular js & three.js
PDF
Developing large scale JavaScript applications
PDF
Javascript MVVM with Vue.JS
PDF
Building a js widget
PDF
jQuery Internals + Cool Stuff
PDF
VueJS Introduction
PDF
JavaScript Library Overview
PDF
MVC pattern for widgets
PDF
Client Side MVC & Angular
PDF
Modern frontend development with VueJs
PPTX
Vue.js + Django - configuración para desarrollo con webpack y HMR
PDF
Vue js 大型專案架構
PDF
AngularJS - Overcoming performance issues. Limits.
PPTX
The Many Ways to Build Modular JavaScript
PPT
Js unit testing
PDF
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
PDF
An introduction to Vue.js
PDF
Test slideshare document
PDF
Basic Tutorial of React for Programmers
Backbone.js
Integrating Angular js & three.js
Developing large scale JavaScript applications
Javascript MVVM with Vue.JS
Building a js widget
jQuery Internals + Cool Stuff
VueJS Introduction
JavaScript Library Overview
MVC pattern for widgets
Client Side MVC & Angular
Modern frontend development with VueJs
Vue.js + Django - configuración para desarrollo con webpack y HMR
Vue js 大型專案架構
AngularJS - Overcoming performance issues. Limits.
The Many Ways to Build Modular JavaScript
Js unit testing
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
An introduction to Vue.js
Test slideshare document
Basic Tutorial of React for Programmers
Ad

Similar to Clean Javascript (20)

PDF
Unit Testing in JavaScript with MVC and QUnit
PDF
Viking academy backbone.js
PDF
Building a JavaScript Library
PDF
PPTX
5 Tips for Better JavaScript
PPTX
CT presentatie JQuery 7.12.11
PDF
Javascript: the important bits
PDF
Intro to Advanced JavaScript
PDF
Writing Maintainable JavaScript
PPTX
Awesomeness of JavaScript…almost
PDF
Cleaner, Leaner, Meaner: Refactoring your jQuery
PPTX
Javascript And J Query
PDF
The Beauty of Java Script
KEY
User Interface Development with jQuery
PPT
Web Optimization Summit: Coding for Performance
PDF
Intro to jQuery @ Startup Institute
PDF
Gitter marionette deck
PPTX
Prototype Framework
PPTX
Taming that client side mess with Backbone.js
PPT
Expert JavaScript tricks of the masters
Unit Testing in JavaScript with MVC and QUnit
Viking academy backbone.js
Building a JavaScript Library
5 Tips for Better JavaScript
CT presentatie JQuery 7.12.11
Javascript: the important bits
Intro to Advanced JavaScript
Writing Maintainable JavaScript
Awesomeness of JavaScript…almost
Cleaner, Leaner, Meaner: Refactoring your jQuery
Javascript And J Query
The Beauty of Java Script
User Interface Development with jQuery
Web Optimization Summit: Coding for Performance
Intro to jQuery @ Startup Institute
Gitter marionette deck
Prototype Framework
Taming that client side mess with Backbone.js
Expert JavaScript tricks of the masters
Ad

More from Ryunosuke SATO (17)

PPTX
片手間JS on Rails
PDF
Ember コミュニティとわたし
PDF
gem の探し方
PDF
Rails あるある
PDF
Node.js を選ぶとき 選ばないとき
PDF
もっとはじめる Ember.js !! ~ Getting started with Ember.js more ~
PDF
はじめる Ember.js!! ~ Getting started with ember.js ~
PDF
How to relaunch "sapporojs.org" ~Introduction to middleman~
PDF
Introduction for Browser Side MVC
PDF
コミュニティのある風景
KEY
capybara で快適なテスト生活を
PDF
Social coding をもっと楽しみたいあなたへ
KEY
Node.jsってどうなの?
KEY
アジャイル的アプローチから見えてきたこと
PDF
脱レガシー化計画
PDF
Pusherとcanvasで作るリアルタイムグラフ
PDF
ServerSideJavaScript
片手間JS on Rails
Ember コミュニティとわたし
gem の探し方
Rails あるある
Node.js を選ぶとき 選ばないとき
もっとはじめる Ember.js !! ~ Getting started with Ember.js more ~
はじめる Ember.js!! ~ Getting started with ember.js ~
How to relaunch "sapporojs.org" ~Introduction to middleman~
Introduction for Browser Side MVC
コミュニティのある風景
capybara で快適なテスト生活を
Social coding をもっと楽しみたいあなたへ
Node.jsってどうなの?
アジャイル的アプローチから見えてきたこと
脱レガシー化計画
Pusherとcanvasで作るリアルタイムグラフ
ServerSideJavaScript

Recently uploaded (20)

PPT
Teaching material agriculture food technology
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Encapsulation theory and applications.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Approach and Philosophy of On baking technology
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Spectroscopy.pptx food analysis technology
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Machine learning based COVID-19 study performance prediction
Teaching material agriculture food technology
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Encapsulation theory and applications.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Electronic commerce courselecture one. Pdf
Advanced methodologies resolving dimensionality complications for autism neur...
Approach and Philosophy of On baking technology
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
Diabetes mellitus diagnosis method based random forest with bat algorithm
Unlocking AI with Model Context Protocol (MCP)
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
20250228 LYD VKU AI Blended-Learning.pptx
Chapter 3 Spatial Domain Image Processing.pdf
Spectroscopy.pptx food analysis technology
Encapsulation_ Review paper, used for researhc scholars
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Machine learning based COVID-19 study performance prediction

Clean Javascript

  • 2. Community for people who like JavaScript. Sapporo.js
  • 23. JavaScript is most popular!
  • 27. ? ? How to face the difficulty
  • 33. point
  • 34. HTML JavaScript
  • 35. HTML JavaScript
  • 36. here! HTML JavaScript
  • 38. - Attach events from outer - problem JavaScript
  • 39. - Attach events from outer - solution HTML JavaScript
  • 40. - Attach events from outer - <a onclick=”showMessage()”>Click me</a> code smell
  • 41. - Attach events from outer - <a id=”showMessage”>Click me</a> var a = document.getElementById(‘showMessage’); a.addEventListener(‘click’, showMessage); improvement
  • 42. - Separate from Selector - problem HTML id class
  • 43. - Separate from Selector - solution HTML id class
  • 44. - Separate from Selector - function showPhoto(photoId) { var photo = document.getElementById(‘photo-’ + photoId); // do ... }
  • 45. - Separate from Selector - function showPhoto(photoId) { var photo = document.getElementById(‘photo-’ + photoId); // do ... } code smell
  • 46. - Separate from Selector - var showPhoto = function(element) { // do ... } var photo = document.getElementById(‘photo-12’); showPhoto(photo); improvement
  • 48. - modulized functions - solution
  • 49. - modulized functions - // users.js var showUserName = function() { // do somethig } var showUserAge = function(){ // do somethig } var validateUserForm = function() { // do somethig } code smell
  • 50. - modulized functions - // users.js var showUserName = function() { // do somethig } global var showUserAge = function(){ // do somethig } var validateUserForm = function() { // do somethig }
  • 51. - modulized functions - // users.js var users = {}; global users.showName = function () { // do somethig } users.showAge = function (){ // do somethig } users.validateForm = function () { // do somethig }
  • 52. - modulized functions - // users.js (function(global) { global.users = {}; global users.showName = function () { // do somethig } // ... )(this); improvement
  • 55. overwrite behavior - // using jQuery $(‘a#showDialog’).click(function() { $.ajax(‘/about’, { success: function(html) { // do something... } }); }); code smell
  • 56. overwrite behavior - // using jQuery $(‘a#showDialog’).click(function() { $.ajax($(this).attr(‘href’), { success: function(html) { // do something... } }); }); improvement
  • 58. shallow scope - solution 2 function → this
  • 59. shallow scope - // using jQuery var $elements = $(‘a#remote’); $elements.click(function() { var url = $(this).attr(‘href’); $.ajax(url, { success: function(html) { var text = $(html).text(); $element.text(text); } }); return false; });
  • 60. shallow scope - // using jQuery var $elements = $(‘a#remote’); $elements.click(function() { deep var url = $(this).attr(‘href’); $.ajax(url, { success: function(html) { var text = $(html).text(); $element.text(text); } }); return false; }); code smell
  • 61. shallow scope - // using jQuery var $elements = $(‘a#remote’); $elements.click(function() { var url = $(this).attr(‘href’); $.ajax(url, { success: function(html) { var text = $(html).text(); $(this).text(text); }, context: this }); return false; }); improvement
  • 62. DOM - DOM to model - problem DOM
  • 63. DOM - DOM to model - solution DOM
  • 64. DOM - DOM to model - var element = document.getElementById(‘message’); element.addEventListener(‘click’, function() { // this == element if (this.getAttribute(‘data-is-checked’)) { this.setAttribute(‘data-is-checked’, true); this.innerText = ‘clicked!’; } }); code smell
  • 65. DOM - DOM to model - var domToModel = function(element, Model) { var method, name, object, parent, proto; model = Object.create(element); proto = Model.prototype; for (name in proto) { method = proto[name]; model[name] = method; } Model.apply(model); return model; }; var CustomElement = function() {}; CustomElement.prototype.showText = function() { if (!this.getAttribute(‘data-is-checked’)) { var element = document.getElementById(‘message’); this.setAttribute(‘data-is-checked’, true); var model = domToModel(element, CustomElement); this.innerText = ‘clicked!’; model.addEventListener(‘click’, function() { } model.showText(); }; });
  • 66. DOM - DOM to model - var domToModel = function(element, Model) { var method, name, object, parent, proto; model = Object.create(element); proto = Model.prototype; for (name in proto) { method = proto[name]; model[name] = method; } Model.apply(model); return model; }; var CustomElement = function() {}; CustomElement.prototype.showText = function() { if (!this.getAttribute(‘data-is-checked’)) { var element = document.getElementById(‘message’); this.setAttribute(‘data-is-checked’, true); var model = domToModel(element, CustomElement); this.innerText = ‘clicked!’; model.addEventListener(‘click’, function() { } model.showText(); }; });
  • 67. DOM - DOM to model - var domToModel = function(element, Model) { var method, name, object, parent, proto; model = Object.create(element); proto = Model.prototype; for (name in proto) { method = proto[name]; model[name] = method; } Model.apply(model); return model; }; var CustomElement = function() {}; CustomElement.prototype.showText = function() { if (!this.getAttribute(‘data-is-checked’)) { var element = document.getElementById(‘message’); this.setAttribute(‘data-is-checked’, true); var model = domToModel(element, CustomElement); this.innerText = ‘clicked!’; model.addEventListener(‘click’, function() { } model.showText(); }; }); improvement
  • 68. - separate logic with view - problem
  • 69. - separate logic with view - solution
  • 70. - separate logic with view - function createTimer() { var timerId; var startTimer = function(millisec) { timerId = setTimeout(function() { $(‘.timeout’).text(‘finished’); }, millisec); } var stopTimer = function() { clearTimeout(timerId); } return { startTimer: startTimer, stopTimer: stopTimer } }
  • 71. - separate logic with view - function createTimer() { var timerId; var startTimer = function(millisec) { timerId = setTimeout(function() { $(‘.timeout’).text(‘finished’); view }, millisec); } var stopTimer = function() { clearTimeout(timerId); } return { startTimer: startTimer, stopTimer: stopTimer } } code smell
  • 72. - separate logic with view - function Timer(millisec) { this. millisec = millisec; this.callbacks = []; this.timerId = null; } Timer.prototype.afterFinish = function(callback) { return this.callbacks.push(callback); }; Timer.prototype.start = function() { var callbacks = this.callbacks; this.timerId = setTimeout(function() { var callback, i, length; for (i = 0, length = callbacks.length; i < length; i++) { var timer = new Timer(1000); callback = callbacks[i]; timer.afterFinish(function() { callback(); $('.timer .message').text('Finished!!'); } }); }, this. millisec); timer.start(); }; Timer.prototype.stop = function() { clearTimeout(this.timerId); }
  • 73. - separate logic with view - function Timer(millisec) { this. millisec = millisec; this.callbacks = []; } this.timerId = null; model Timer.prototype.afterFinish = function(callback) { return this.callbacks.push(callback); }; Timer.prototype.start = function() { view var callbacks = this.callbacks; this.timerId = setTimeout(function() { var callback, i, length; for (i = 0, length = callbacks.length; i < length; i++) { var timer = new Timer(1000); callback = callbacks[i]; timer.afterFinish(function() { callback(); $('.timer .message').text('Finished!!'); } }); }, this. millisec); timer.start(); }; Timer.prototype.stop = function() { clearTimeout(this.timerId); } improvement
  • 89. Shall we learn about Clean JavaScript?