JavaScript Code Organizations, Patterns Slides - Zach Dennis
JavaScript Practices & Design Patterns
-
Upload
cristi-salcescu -
Category
Software
-
view
48 -
download
1
Transcript of JavaScript Practices & Design Patterns
![Page 1: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/1.jpg)
JavaScript Practices & Design Patterns
Salcescu CristianV0.5.2
![Page 2: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/2.jpg)
Function Overloadingfunction log(a,b){ if(arguments.length === 1){ if(typeof(a) === "number") $("#log").append("<br />number:").append(a); else $("#log").append("<br />string:").append(a); } else $("#log").append("<br />2 arguments:").append(a + " " + b); }
log(1);log("Hello!");log(1,2);
![Page 3: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/3.jpg)
Method chaining
• a common syntax for calling multiple functions on the same object
$('#my-div').css('background', 'blue').height(100).slideUp(2000).slideDown(2000);
![Page 4: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/4.jpg)
Timer Patterns
• setInterval/clearInterval• setTimeout/clearTimeout
- all JavaScript in a browser executes on a single thread. JavaScript is single threaded.
- Exception : Web Workers, but they cannot access the DOM.
- Two functions can't run at the same time.
![Page 5: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/5.jpg)
Issues with setInterval
![Page 6: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/6.jpg)
Recursive setTimeout Patternvar i = 1;function func() {
alert(i++);timer = setTimeout(func, 2000);
} var timer = setTimeout(func, 2000);
![Page 7: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/7.jpg)
Throttle
- new function that will execute no more than once every delay milliseconds
_.throttle(fn, delay);
![Page 8: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/8.jpg)
Debounce
- a function that will execute only once, for a group of sequential calls
_.debounce(fn, delay);
![Page 9: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/9.jpg)
Template engine• Separates JS business logic from the html views• Libraries : Handlebars, Hogan
<div id="editContainer">Edit Loading...</div><script type="text/template" id="editTemplate"> <form> FName : <input type="text" value={{fname}} name="fname" /><br/> LName : <input type="text" value={{lname}} name="lname" /><br/> <button type="button" class="save">Save</button> </form></script>
function render(){ var person = {fname: "Mihai", lname: "Ionescu"}; var template = Handlebars.compile($('#editTemplate').html()); var html = template(person); $el.html(html); }
![Page 10: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/10.jpg)
Publish–Subscribe Pattern
• publish–subscribe is a messaging pattern • Senders of messages are called publishers• Receivers of the messages are called subscribers• publishers do not program the messages to be sent
directly to specific receivers, they instead, publish messages without knowledge of what, if any, subscribers there may be.
• subscribers express interest in one or more message types, and only receive messages that are of interest, without knowledge of what, if any, publishers there are.
![Page 11: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/11.jpg)
Publish–Subscribe Pattern
• jQuery$.event.trigger("itemSaved", data);$(document).on("itemSaved", onItemSaved);
- Amplifyamplify.publish( string topic, ... )amplify.subscribe( string topic, function callback )
- Angular$rootScope.$broadcast("itemSaved", data);$scope.$on("itemSaved", function(event, data) {});
![Page 12: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/12.jpg)
Publish–Subscribe Patternvar EVENTS = { buttonClicked : "buttonClicked" };
(function(){ $(function(){ $("#btn").click(function() { amplify.publish( EVENTS.buttonClicked, { message: "Hi!" } ); }); }); }());
(function(){ amplify.subscribe( EVENTS.buttonClicked, function( data ) { alert( data.message ); });}());
![Page 13: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/13.jpg)
Promises- A reference to an async call
function log(text){ $("#container").append(text).append("<br />");}function asynCall(time, text){ var deferred = $.Deferred(); setTimeout(function(){ log(text); deferred.resolve(); }, time); return deferred.promise();}
function asynCall1(){ return asynCall(1000, "1"); };function asynCall2(){ return asynCall(2000, "2"); };function asynCall3(){ return asynCall(3000, "3"); };
var promise1 = asynCall1();var promise2 = asynCall2();var promise3 = asynCall3();
promise1.done(function() { log("1 is done");});$.when(promise1, promise2, promise3).done(function() { log("all done");});
![Page 14: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/14.jpg)
async Libraryasync.parallel([ function(callback){ setTimeout(function(){ callback(null, 'one'); }, 3000); }, function(callback){ setTimeout(function(){ callback(null, 'two'); }, 1000); }], function(err, results){ log(results[0]); log(results[1]); });
function log(text) { $("#log").append(text).append("<br />"); }
![Page 15: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/15.jpg)
MV* Patterns
• MVC• MVVM
![Page 16: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/16.jpg)
MVC
• Model – data, information to be displayed• View – the presentation, HTML template• Controller – manages the communication
between View and Model, encapsulates the business logic
![Page 17: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/17.jpg)
MVVM
• Model – data, information to be displayed• View – the presentation, HTML template• The ViewModel can be considered a
specialized Controller that acts as a data converter. It changes Model information into View information, passing commands from the View to the Model. Behaviour/Business Logic is encapsulated here.
![Page 18: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/18.jpg)
Frameworks
- Backbone- Knockout- Angular
- MVVM separation- Two-way Data Binding- Dependency Injection- Pub/Sub utility
![Page 19: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/19.jpg)
Backbone - View<div id="listContainer">List Loading...</div><div id="editContainer">Edit Loading...</div><script type="text/template" id="editTemplate"> <form> FName : <input type="text" value={{fname}} name="fname" /><br/> LName : <input type="text" value={{lname}} name="lname" /><br/> <button type="button" class="save">Save</button> </form></script>
![Page 20: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/20.jpg)
Backbone - ViewModelvar app = new Backbone.Marionette.Application();
var itemService = { save : function(data) { alert("APIService save : " + data); }}
app.module("editModule", function(editModule, app, Backbone, Marionette, $, _, itemService){ var person = {fname: "Mihai", lname: "Ionescu"}; var EditView = Backbone.View.extend({ el: '#editContainer', initialize: function(){ this.render(); }, render: function(){ var template = Handlebars.compile($('#editTemplate').html()); var html = template(person); this.$el.html(html); }, events: { "click .save" : "save" }, save: function() { var data = $("form", this.$el).serialize(); itemService.save(data); Backbone.trigger('itemSaved', data); } });
var editView = new EditView();}, itemService);
![Page 21: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/21.jpg)
Backbone – Two-way data binding
var app = new Backbone.Marionette.Application();
var itemService = { save : function(data) { alert("APIService save : " + data); }}
app.module("editModule", function(editModule, app, Backbone, Marionette, $, _, itemService){ var personModel = new Backbone.Model({ fname: "Mihai", lname: "Ionescu" }); var EditView = Backbone.View.extend({ el: '#editContainer', model: personModel, bindings: { '[name=fname]': 'fname', '[name=lname]': 'lname' }, initialize: function(){ this.render(); }, render: function(){ this.stickit(); }, events: { "click .save" : "save" }, save: function() { var data = this.model.get("fname"); itemService.save(data); Backbone.trigger('itemSaved', data); } });
var editView = new EditView();}, itemService);
![Page 22: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/22.jpg)
Knockout - View<div id="listContainer"><span data-bind="text: message">List Loading...</span></div><div id="editContainer"> <form> FName : <input type="text" name="fname" data-bind="value: fname" /><br/> LName : <input type="text" name="lname" data-bind="value: lname" /><br/> Full Name : <span data-bind="text: fullName"></span> <br /> <button type="button" class="save" data-bind='click: save' >Save</button> </form></div>
![Page 23: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/23.jpg)
Knockout - ViewModelvar itemService = { save : function(data) { alert("APIService save : " + data); }}
var EditViewModel = function(person) { this.fname = ko.observable(person.fname); this.lname = ko.observable(person.lname); this.fullName = ko.computed(function() { return this.fname() + " " + this.lname(); }, this); this.save = function() { var data = this.fname(); itemService.save(data); ko.postbox.publish("itemSaved", data); }; };
![Page 24: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/24.jpg)
Angular - View<div ng-app="app"><div id="listContainer" ng-controller="listCtrl" > <span ng-bind="message" >List Loading...</span></div><div id="editContainer" ng-controller="editCtrl" > <form> FName : <input type="text" name="fname" ng-model="person.fname" /><br/> LName : <input type="text" name="lname" ng-model="person.lname" /><br/> Full Name : <span ng-bind="fullName()" ></span> <br /> <button type="button" class="save" ng-click="save()" >Save</button> </form></div></div>
![Page 25: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/25.jpg)
Angular - Controllervar app = angular.module("app", []);app.controller("editCtrl", ["$scope", "$rootScope", "itemService", function($scope,$rootScope, itemService){ var person = { fname: "Mihai", lname: "Ionescu"}; $scope.person = person; $scope.fullName = function() { return $scope.person.fname + " " + $scope.person.lname; }; $scope.save = function(){ var data = $scope.person.fname; itemService.save(data); $rootScope.$broadcast("itemSaved", data); }}]);
app.factory( 'itemService', function(){ return { save : function(data) { alert("APIService save : " + data) } }});
![Page 26: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/26.jpg)
Modules
- Split the HTML page in UI components (Views)- Create JS Controllers for every View. Follow the
Module Pattern when defining the JS Controller- All DOM- centric code related to a View should
stay in its Controller. – Comunicate between Controllers using the
Publish-Subscribe Pattern– Don’t create or update global objects. All required
service libraries should be passed in
![Page 27: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/27.jpg)
View<div id="listContainer">List Loading...</div><div id="editContainer">Edit Loading...</div><script type="text/template" id="editTemplate"> <form> FName : <input type="text" value={{fname}} name="fname" /><br/> LName : <input type="text" value={{lname}} name="lname" /><br/> <button type="button" class="save">Save</button> </form></script>
![Page 28: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/28.jpg)
Logicvar services = {};services.itemService = (function(){ function save(data) { alert("APIService save : " + data); }; return { save : save }}());
![Page 29: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/29.jpg)
(function($, services){ "use strict"; var $el, el = "#editContainer"; function initElements(){ $el = $(el); } function render(){ var person = {fname: "Mihai", lname: "Ionescu"}; var template = Handlebars.compile($('#editTemplate').html()); var html = template(person); $el.html(html); } function initEvents(){ $(".save", $el).on("click", save); } function save() { var data = $("form", $el).serialize(); services.itemService.save(data); $.event.trigger("itemSaved", data); }
$(function(){ initElements(); render(); initEvents(); }); }(jQuery, services));
![Page 30: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/30.jpg)
Dependency Management• angular• ng-di library
app.controller("editCtrl", ["$scope", "$rootScope", "itemService", function($scope,$rootScope, itemService){
…}]);
app.factory( 'itemService', function(){ return {
… }});
![Page 31: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/31.jpg)
jQuery Plugin- Create reusable UI components
<div class="show-more"> <button class="btn-toggle">Toggle</button> <div class="content"> text text<br /> text text<br /> text text<br /> </div></div><div class="show-more"> <button class="btn-toggle">Toggle</button> <div class="content"> text text<br /> text text<br /> text text<br /> </div></div>
![Page 32: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/32.jpg)
jQuery Plugin$.fn.showMore = function() { var $set = this, $el; function createToggleHendler($el){ return function(){ $(".content", $el).toggle(); } } $set.each(function() { $el = $(this); $(".btn-toggle", $el).on("click", createToggleHendler($el)); }); return $set; };
$(function() { $(".show-more").showMore();});
![Page 33: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/33.jpg)
angular Directive- encapsulate all DOM manipulation and create reusable UI components
var app = angular.module('myapp', []);
app.directive('showMore', function() { function createToggleHendler($el){ return function(){ $(".content", $el).toggle(); } } return { restrict: 'C', link : function($scope, element, attrs) { $(".btn-toggle", element).on("click", createToggleHendler(element)); } };});
![Page 34: JavaScript Practices & Design Patterns](https://reader034.fdocuments.us/reader034/viewer/2022042716/55b6e2f8bb61eb7e268b485f/html5/thumbnails/34.jpg)
ResourcesPluralsight - Large Scale JavaScript on Client and ServerPluralsight – JavaScript Design Patterns