JavaScript Best Practices, Backbone.js, and Mario for the PHP Develop
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

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

  • 15,253 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
15,253
On Slideshare
14,814
From Embeds
439
Number of Embeds
11

Actions

Shares
Downloads
122
Comments
2
Likes
25

Embeds 439

https://twitter.com 187
http://lanyrd.com 150
http://waffleme.com 81
http://coderwall.com 6
http://samples.dev.talentlms.com 4
https://si0.twimg.com 4
http://us-w1.rockmelt.com 2
http://www.linkedin.com 2
http://nodeslide.herokuapp.com 1
http://www.onlydoo.com 1
http://www.php-talks.com 1

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