JavaScript Best Practices, Backbone.js, and Mario for the PHP Develop

  • 14,800 views
Uploaded on

Time to talk your JavaScript to the next level. Join us as we take a normal jQuery document.ready block and start to break it into objects, use the prototype model, investigate scope, and …

Time to talk your JavaScript to the next level. Join us as we take a normal jQuery document.ready block and start to break it into objects, use the prototype model, investigate scope, and self-executing JavaScript blocks.

We'll be guided in our journey by Mario and his friends, as well as a full-demo and source code, complete with a poor-man's animation of Luigi kicking ass with a fireball. We'll also run through the basics of Backbone.js and which parts to use and avoid based on your application.

And because you're a PHP developer, we'll see how JavaScript object-oriented principles would look like if they were written in PHP.

http://weaverryan.github.com/php-js-playground/

https://github.com/weaverryan/php-js-playground

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
14,800
On Slideshare
0
From Embeds
0
Number of Embeds
5

Actions

Shares
Downloads
122
Comments
2
Likes
25

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. JAVASCRIPT BEST PRACTICES & BACKBONE.JS FOR THE PHP DEVELOPER Ryan Weaver @weaverryanThursday, May 24, 12
  • 2. 7 tips for writing JavaScript like a jerk + What to take and leave in Backbone.jsThursday, May 24, 12
  • 3. Who is this dude? • Co-author of the Symfony2 Docs • KnpLabs US - Symfony consulting, training, Kumbaya • Writer for KnpUniversity.com screencasts • Fiancee of the much more talented @leannapelham -----> June 9th, 2012! http://www.knplabs.com/en @weaverryan http://www.github.com/weaverryanThursday, May 24, 12
  • 4. Chapter 1: Java$criptQuery Look mom, I’m a JavaScript professional @weaverryanThursday, May 24, 12
  • 5. 1. jQuery(document).ready(...) 2. 1500 lines, with deeply nested anonymous functions 3. Profit! $$$ @weaverryanThursday, May 24, 12
  • 6. Too soon? ... sry fb, luv u kthxbye @weaverryanThursday, May 24, 12
  • 7. The brains behind this presentation...Thursday, May 24, 12
  • 8. source: http://www.geeky-gadgets.com/super-mario-bros-matryoshka-dolls/Thursday, May 24, 12
  • 9. Thursday, May 24, 12
  • 10. <div class="mario box"> .mario <div class="luigi box"> .luigi <div class="kick-butt">...</div> <a href="#" class="peach box"> .peach </a> </div></div>Thursday, May 24, 12
  • 11. Let’s kick some arse! jQuery(document).ready(function() { var $luigi = $(.event-details .luigi); $luigi.click(function() { $(this).addClass(active); return false; }); });Thursday, May 24, 12
  • 12. DEMO!!!!! http://bit.ly/php-js-demo 0 - The starting pointThursday, May 24, 12
  • 13. Princess Pro-tip Instead of listening to this guy drone on, just find, fork and play with the code yourself! http://bit.ly/php-js-playThursday, May 24, 12
  • 14. ‣ Click either .luigi or .peach ‣ the .luigi wrapper gets the active classThursday, May 24, 12
  • 15. Mario’s bad JavaScript tip #1: Ignore the jQuery “event” object, it’s probably stupid... http://bit.ly/php-js-demo 01 - The jQuery Event @weaverryanThursday, May 24, 12
  • 16. Events happenThursday, May 24, 12
  • 17. Event Click! 1) You click! 2) An event travels up the treeThursday, May 24, 12
  • 18. Browser event versus jQuery event ‣ The browser event contains all the information about what happened ‣the jQuery event cleans up cross- browser compatibility uglinessThursday, May 24, 12
  • 19. $luigi.click(function(event) { // ... }); ‣ event.target: The actual element that received the click ‣ event.currentTarget: The element that this listener was attached toThursday, May 24, 12
  • 20. $luigi.click(function(event) { // ... }); Our listener is registered on .luigiThursday, May 24, 12
  • 21. If you click .peach: event.target: .peach event.currentTarget: .luigiThursday, May 24, 12
  • 22. If you click .luigi: event.target: .luigi event.currentTarget: .luigiThursday, May 24, 12
  • 23. event.currentTarget == this * unless you screw with scope, which we’ll see!Thursday, May 24, 12
  • 24. $luigi.click(function(event) { // these are the same! $(event.currentTarget) .addClass(active); $luigi.addClass(active); });Thursday, May 24, 12
  • 25. Preventing the damn “#” on the URL $luigi.click(function() { $(this).addClass(active); return false; });Thursday, May 24, 12
  • 26. Princess Pro-tip return false stops propagation, and is a great way to screw with your teammate’s events http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/Thursday, May 24, 12
  • 27. ... but if you like your coworkers... $luigi.click(function(event) { event.preventDefault(); // ... }); The event keeps traveling up the DOMThursday, May 24, 12
  • 28. Bad JavaScript moral #1: jQuery’s event object is a dangerous source of useful information and control @weaverryanThursday, May 24, 12
  • 29. Mario bad JavaScript tip #2: Avoid using objects: they threaten to organize your code... and are creepy... http://bit.ly/php-js-demo 02 - Basic jQuery Objects @weaverryanThursday, May 24, 12
  • 30. A PHP object @weaverryanThursday, May 24, 12
  • 31. <?php class MagicBoxes { public function initializeClick($wrapper) { // ... } } $magicBoxes = new MagicBoxes(); $magicBoxes->initializeClick(something);Thursday, May 24, 12
  • 32. A JavaScript object @weaverryanThursday, May 24, 12
  • 33. var MagicBoxes = { someProperty: 0, initializeClick: function($container) { // ... } }; MagicBoxes.initializeClick(something);Thursday, May 24, 12
  • 34. Just like with PHP, you can choose to organize your code into objects and functions @weaverryanThursday, May 24, 12
  • 35. var MagicBoxes = { initializeClick: function($container) { $container.find(.luigi) .click(this._handleLuigiClick); }, _handleLuigiClick: function(event) { event.preventDefault(); $luigi.addClass(active); } }; jQuery(document).ready(function() { var $wrap = $(.mario-world); MagicBoxes.initializeClick($wrap); });Thursday, May 24, 12
  • 36. Princess Pro-tip Be careful with objects, they can increase readability, which threatens job securityThursday, May 24, 12
  • 37. Objects: Advantages ‣ All of the logic of this “mini-app” is wrapped up inside a named object ‣ The jQuery document.ready is skinny: contains simple, descriptive calls to the object ‣ The object methods are reusableThursday, May 24, 12
  • 38. Object Scope // hola! I’m just a local variable var MagicBoxes = { // ... }; // I’m a global variable, available anywhere window.MagicBoxes = { };Thursday, May 24, 12
  • 39. the “window” window.foo = foo-window; console.log(foo); // prints "foo-window" bar = bar-global; console.log(window.bar); // prints "bar-global"Thursday, May 24, 12
  • 40. Bad JavaScript moral #2: Using global objects risks organizing your code into separate, distinct units @weaverryanThursday, May 24, 12
  • 41. Mario’s bad JavaScript tip #3: JavaScript’s “prototype” object model is too scary to use http://bit.ly/php-js-demo 03 - Intro to the JS Prototype @weaverryanThursday, May 24, 12
  • 42. Everything is an objectThursday, May 24, 12
  • 43. An object with a property var object1 = { fooProperty: foo! } console.log(object1.fooProperty); // prints “foo!”Thursday, May 24, 12
  • 44. Also an object with a property var alsoAnObject = function() { return foo-return! }; alsoAnObject.barProperty = bar!; console.log(alsoAnObject.barProperty); // prints “bar!” console.log(alsoAnObject()); // prints “foo-return!”Thursday, May 24, 12
  • 45. In PHP, we can create a class and then instantiate many instances @weaverryanThursday, May 24, 12
  • 46. <?php class MagicBoxes { public function __construct($option) { // ... } } $magicBoxes1 = new MagicBoxes(foo); $magicBoxes2 = new MagicBoxes(bar);Thursday, May 24, 12
  • 47. How can we do this in JavaScript? @weaverryanThursday, May 24, 12
  • 48. Imagine if we could do this craziness in PHP @weaverryanThursday, May 24, 12
  • 49. ImaginationLand PHP code $magicBox = function($var) { $this->var = $var; $this->initialize(); }; $magicBox->prototype->initialize = function() { var_dump($this->var); }; $magicBoxObj = new $magicBox(something); // causes "something" to be printedThursday, May 24, 12
  • 50. Yep, that’s how it works in JavaScript! @weaverryanThursday, May 24, 12
  • 51. #1: Create a function window.MagicBoxes = function($container) { this.$el = $container; this.initialize(); };Thursday, May 24, 12
  • 52. #2: Add things to your future object MagicBoxes.prototype.initialize = function() { var $luigi = this.$el.find(.luigi); $luigi.click(function(event) { event.preventDefault(); $(this).toggleClass(active); }); };Thursday, May 24, 12
  • 53. #2: Add things to your future object MagicBoxes.prototype.initialize = function() The “prototype” is a magic place where you stick “future” things that will become a part of the eventual new objectThursday, May 24, 12
  • 54. #3: Instantiate your new object jQuery(document).ready(function() { var $mario = $(.mario-world); var magicBoxApp = new MagicBoxes($mario); });Thursday, May 24, 12
  • 55. #4: Beers! @weaverryanThursday, May 24, 12
  • 56. Princess Pro-tip Your speaker is a liar and a thief. Using the prototype is for sissies!Thursday, May 24, 12
  • 57. Bowser rebuttal Don’t listen to her! A gentleman and scholar named Garrison Locke is going to teach us the prototypical object model of JavaScript tomorrow at 11:30 AMThursday, May 24, 12
  • 58. Peach come-back No you didn’t! Mario and I both agree that using objects in JavaScript is all weird! Viva the 1500 line jQuery document.ready!Thursday, May 24, 12
  • 59. Bowser final word Seriously, this is why I fight against you guysThursday, May 24, 12
  • 60. Bowser final word Your ignorance may seem blissful, but you work as a detriment towards the larger cause of evolving and learning as a communityThursday, May 24, 12
  • 61. Bowser final word Thank God Garrison Locke will be teaching us Object- oriented JavaScript tomorrow at 11:30 AM.Thursday, May 24, 12
  • 62. Bowser final word He’s a much better speaker than this guyThursday, May 24, 12
  • 63. Ryan does damage control on his presentation Dude, I’m right hereThursday, May 24, 12
  • 64. Purple is a manly color You really like that shirt...Thursday, May 24, 12
  • 65. Bad JavaScript moral #3: Don’t use jQuery’s prototype or go to Garrison Locke’s presentation tomorrow if you want unreadable JavaScript @weaverryanThursday, May 24, 12
  • 66. Mario’s bad JavaScript tip #4: “this” probably always means “this”... don’t ask questions http://bit.ly/php-js-demo 04 - Scoping Concerns @weaverryanThursday, May 24, 12
  • 67. ImaginationLand PHP code $magicBox = new MagicBoxes(foo); $foo = new Foo(); // imaginary PHP function // this calls $magicBox->doSomething() // BUT, forces $this to actual be $foo inside // that object. Madness! call_func($magicBox, doSomething, $foo);Thursday, May 24, 12
  • 68. With JavaScript objects, “this” may not always be what you think it is @weaverryanThursday, May 24, 12
  • 69. window.Boxes = function($container) { this.$el = $container; var $luigi = this.$el.find(.luigi); $luigi.on(click, this._luigiClick); }; Boxes.prototype._luigiClick = function(event) { event.preventDefault(); this.luigiFights($(this)); }; Boxes.prototype.luigiFights = function($luigi) { $luigi.toggleClass(active); };Thursday, May 24, 12
  • 70. Is it our Boxes object? Boxes.prototype._luigiClick = function(event) { event.preventDefault(); this.luigiFights($(this)); }; Or is it the DOM element that triggered the jQuery event?Thursday, May 24, 12
  • 71. “this” is actually the DOM element that triggered the jQuery event Boxes.prototype._luigiClick = function(event) { event.preventDefault(); this.luigiFights($(this)); }; so “this” will not work pun intended...Thursday, May 24, 12
  • 72. window.Boxes = function($container) { this.$el = $container; var $luigi = this.$el.find(.luigi); $luigi.on( click, $.proxy(this._luigiClick, this) ); }; Boxes.prototype._luigiClick = function(event) { event.preventDefault(); this.makeLuigiFight($(event.currentTarget)); };Thursday, May 24, 12
  • 73. window.Boxes = function($container) { this.$el = $container; var $luigi = this.$el.find(.luigi); $luigi.on( click, $.proxy(this._luigiClick, this) ); }; $.proxy forces _luigiClick to have “this” as this object when calledThursday, May 24, 12
  • 74. event.currentTarget returns the element that was registered on this event (formerly “this”) Boxes.prototype._luigiClick = function(event) { event.preventDefault(); this.makeLuigiFight($(event.currentTarget)); };Thursday, May 24, 12
  • 75. Mario’s bad JavaScript tip #5: Avoid jQuery.extend so that you can repeat yourself as much as possible: DRY* * definitely repeat yourself http://bit.ly/php-js-demo @weaverryan 05 - jQuery extendsThursday, May 24, 12
  • 76. PHP ImaginationLand // foo has printFoo() method on it $foo = new Foo(); // bar has a printBar() method on it $bar = new Bar(); // now $fooBar has both methods! $fooBar = extend($foo, $bar); $fooBar->printFoo(); $fooBar->printBar();Thursday, May 24, 12
  • 77. var foo = { foo: function() { return foo-string; } }; var bar = { bar: function() { return bar-string; } }; var fooBar = $.extend(foo, bar); console.log(fooBar.foo(), fooBar.bar());Thursday, May 24, 12
  • 78. Writing bad JavaScript tip #6: Avoid using “delegate” events, and instead constantly worry about re-attaching events to new elements http://bit.ly/php-js-demo 06 - Delegate events @weaverryanThursday, May 24, 12
  • 79. Can you see the difference? this.$el.find(.luigi).on( click, $.proxy(this._luigiClick, this) ); this.$el.on( click, .luigi, $.proxy(this._luigiClick, this) );Thursday, May 24, 12
  • 80. this.$el.find(.luigi)on( click, $.proxy(this._luigiClick, this) ); Since the event is registered specifically on “.luigi”, if any new “.luigi” elements are added, they will not response to this eventThursday, May 24, 12
  • 81. The event is registered on the wrapper, but looks for “.luigi”. If new “.luigi” elements are added to the wrapper, they will automatically trigger the event this.$el.on( click, .luigi, $.proxy(this._luigiClick, this) );Thursday, May 24, 12
  • 82. jQuery.live? $(.foo).live(click, ...); really just means this $(body).on(click, .foo, ...);Thursday, May 24, 12
  • 83. Mario’s bad JavaScript tip #7: Self-executing JavaScript blocks are just plain scary looking http://bit.ly/php-js-demo 07 - Self-executing blocks @weaverryanThursday, May 24, 12
  • 84. PHP Imaginationland $dbConn = ; // initialize this $ourPreparedObject = (function($db) { $a = 5; $b = 10; $db->execute(...); // ... a lot more complex stuff return $someObject; })($dbConn); $ourPreparedObject->callSomething();Thursday, May 24, 12
  • 85. JavaScript Real Life window.MagicBoxes = (function($) { return { // do a bunch of craziness }; })(jQuery); MagicBoxes.someMethod();Thursday, May 24, 12
  • 86. This is just a function... window.MagicBoxes = (function($) { return { // do a bunch of craziness }; })(jQuery); MagicBoxes.someMethod();Thursday, May 24, 12
  • 87. Then we execute it, and pass in an argument window.MagicBoxes = (function($) { return { // do a bunch of craziness }; })(jQuery); MagicBoxes.someMethod();Thursday, May 24, 12
  • 88. The function does any craziness it wants, but returns something window.MagicBoxes = (function($) { return { // do a bunch of craziness }; })(jQuery); MagicBoxes.someMethod();Thursday, May 24, 12
  • 89. which we assign to a variable and then use window.MagicBoxes = (function($) { return { // do a bunch of craziness }; })(jQuery); MagicBoxes.someMethod();Thursday, May 24, 12
  • 90. And that’s it! ‣ Makes isolated chunks of code ‣ Used by most JavaScript libraries to isolate their code from yoursThursday, May 24, 12
  • 91. Backbone.js! @weaverryanThursday, May 24, 12
  • 92. Mario’s bad JavaScript tip #8: Don’t use, or over-use Backbone.js http://bit.ly/php-js-demo 08 - A Backbone View @weaverryanThursday, May 24, 12
  • 93. What is Backbone? ‣ Set of tools for creating heavy front- end applications: * views * models * router @weaverryanThursday, May 24, 12
  • 94. Views A formalized method for creating a JavaScript object that “manages” a DOM elementThursday, May 24, 12
  • 95. Views We’ve been building an object that’s very similar to a Backbone viewThursday, May 24, 12
  • 96. var MagicBoxes = Backbone.View.extend({ events: { click .luigi: _luigiClick }, initialize: function() { _.bindAll(this, _luigiClick) }, _luigiClick: function(event) { event.preventDefault(); $(event.currentTarget) .toggleClass(active); } }); var magicBoxApp = new MagicBoxes({ el: $(.mario-world) });Thursday, May 24, 12
  • 97. var MagicBoxes = Backbone.View.extend({ events: { click .luigi: _luigiClick }, initialize: function() { _.bindAll(this, _luigiClick) }, That sure is a simple way to bind to events. And thanks to _luigiClick: function(event) { “delegate” events, when the event.preventDefault(); DOM updates, the events still $(event.currentTarget) fire on new elements! .toggleClass(active); } }); var magicBoxApp = new MagicBoxes({ el: $(.mario-world) });Thursday, May 24, 12
  • 98. var MagicBoxes = Backbone.View.extend({ events: { click .luigi: _luigiClick }, initialize: function() { _.bindAll(this, _luigiClick) }, _luigiClick: function(event) { event.preventDefault(); $(event.currentTarget) automatically initialize() is .toggleClass(active); called by Backbone. } }); var magicBoxApp = new MagicBoxes({ el: $(.mario-world) });Thursday, May 24, 12
  • 99. var MagicBoxes = Backbone.View.extend({ events: { click .luigi: _luigiClick }, initialize: function() { _.bindAll(this, _luigiClick) }, _luigiClick: function(event) { _.bindAll is from event.preventDefault(); underscore.js - it does the $(event.currentTarget) same job as jQuery.proxy: .toggleClass(active); } guarantees that “this” is }); this object in that function var magicBoxApp = new MagicBoxes({ el: $(.mario-world) });Thursday, May 24, 12
  • 100. var MagicBoxes = Backbone.View.extend({ events: { click .luigi: _luigiClick }, initialize: function() { _.bindAll(this, _luigiClick) DOM We attach a real }, element to the view by passing it into a pre-made _luigiClick: function(event) { constructor as “el”. In the event.preventDefault(); object, it’s available via $(event.currentTarget) this.el .toggleClass(active); } }); var magicBoxApp = new MagicBoxes({ el: $(.mario-world) });Thursday, May 24, 12
  • 101. Models A formalized object that just holds key-value data on itThursday, May 24, 12
  • 102. var Character = Backbone.Model.extend(); var mario = new Character({ name: Mario }); var peach = new Character({ name: Peach, status: captured }); // change some data peach.set({ status: rescued });Thursday, May 24, 12
  • 103. Events make them wonderful peach.on(change, function(changedModel) { var name = changedModel.get(name); console.log(name + was updated!); }); // will cause "Peach was updated" to log peach.set({ status: rescued });Thursday, May 24, 12
  • 104. var Character = Backbone.Model.extend(); var App = Backbone.View.extend({ initialize: function() { _.bindAll(this, _updateName); this.model.on(change, this._updateName); this._updateName(); }, _updateName: function() { var name = this.model.get(name); this.$(.name).html(name); } }); var mario = new Character({ name: Mario }); var app = new App({ el: $(.mario-world), model: mario });Thursday, May 24, 12
  • 105. var Character = Backbone.Model.extend(); var App = Backbone.View.extend({ initialize: function() { _.bindAll(this, _updateName); this.model.on(change, this._updateName); this._updateName(); }, _updateName: function() { var name = this.model.get(name); this.$(.name).html(name); } }); When the model changes, we can update the DOM anywhere that we’re listening for that changeThursday, May 24, 12
  • 106. Backbone is a great solutionThursday, May 24, 12
  • 107. But do you have a problem?Thursday, May 24, 12
  • 108. Views: Easy win ‣ Easy event binding ‣ An object-oriented structure that’s setup for you already ‣ “Patterns” to follow as you get comfortable @weaverryanThursday, May 24, 12
  • 109. Views: Who Renders? ‣ There are 2 types of Views: Easy 1) Views applied to existing elements Win in the DOM (like our example) 2) Views that are given an empty Depends element, and then render using client- side templates and model data @weaverryanThursday, May 24, 12
  • 110. When to use Models + Views ‣ A highly interactive app that communicates to a PHP API that is never responsible for rendering any HTML @weaverryanThursday, May 24, 12
  • 111. When *not* to use Models + Views ‣ An app where PHP renders HTML ‣ An app where the API isn’t robust @weaverryanThursday, May 24, 12
  • 112. Duplication ‣ If your PHP application renders HTML and you also try to use Backbone Views that render HTML, you’ll need duplicate templates ‣ Do one or the other @weaverryanThursday, May 24, 12
  • 113. Duplication You can potentially duplicate a lot of work both on the client and server sides: ‣ validation ‣ models ‣ templates @weaverryanThursday, May 24, 12
  • 114. Find your Comfort Zone ‣ Not really comfortable with a fully- client side application? Use Backbone views attached to existing DOM element ‣ Feel pretty awesome about doing everything in the browser? Dive in :) @weaverryanThursday, May 24, 12
  • 115. Thanks... Ryan Weaver @weaverryanThursday, May 24, 12
  • 116. ... and we love you! http://joind.in/talk/view/6508 Ryan Weaver @weaverryan Ryan Weaver @weaverryanThursday, May 24, 12