Slide 1

Slide 1 text

JavaScripting for the PHP Developer in 2012 this is not the JavaScript from 1999 Jeff Carouth ZendCon 2012

Slide 2

Slide 2 text

Jeff Carouth tweets jcarouth blogs http://carouth.com checks [email protected] works

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

JavaScript Basics

Slide 5

Slide 5 text

Arrays array(); []; //PHP 5.4+ array(1, 2, 3, 4); array(1, "foo", new stdClass()); array("foo" => "bar", "fizz" => "buzz");

Slide 6

Slide 6 text

Arrays array(); []; //PHP 5.4+ array(1, 2, 3, 4); array(1, "foo", new stdClass()); array("foo" => "bar", "fizz" => "buzz"); []; // new Array(); [1, 2, 3, 4]; [1, "foo", {}]; ["foo": "bar", "fizz": "buzz"]; //ERROR

Slide 7

Slide 7 text

Arrays array(); []; //PHP 5.4+ array(1, 2, 3, 4); array(1, "foo", new stdClass()); array("foo" => "bar", "fizz" => "buzz"); []; // new Array(); [1, 2, 3, 4]; [1, "foo", {}]; ["foo": "bar", "fizz": "buzz"]; //ERROR {"foo": "bar", "fizz": "buzz"}; //NOT an array

Slide 8

Slide 8 text

Arrays typeof []; // 'object' typeof new Array(); // 'object' [3]; // arr.length = 1 new Array(3); // arr.length = 3

Slide 9

Slide 9 text

Objects but NOT Classes Prototypes

Slide 10

Slide 10 text

class Car { private $make; private $model; private $year; public function __construct($make, $model, $year) { $this->make = $make; $this->model = $model; $this->year = $year; } // could use __toString() public function toString() { return $this->year." ".$this->make." ".$this->model; } } $myFirstCar = new Car('Acura', 'Integra', 1990); print $myFirstCar->toString(); // Result: ‘1990 Acura Integra’

Slide 11

Slide 11 text

function Car(make, model, year) { this.make = make; this.model = model; this.year = year; this.toString = function() { return this.year + " " + this.make + " " + this.model; } } var myFirstCar = new Car('Acura', 'Integra', 1990); var myNewCar = new Car('Dodge', 'Charger', 2009); myFirstCar.toString(); // Result: ‘1990 Acura Integra’ myNewCar.toString(); // Result: ‘2009 Dodge Charger’

Slide 12

Slide 12 text

Checking Type gettype($myFirstCar); // object $myFirstCar instanceof Car; // true get_class($myFirstCar); // Car typeof myFirstCar; // 'object' myFirstCar instanceof Car; // true myFirstCar.constuctor; // Car php JavaScript

Slide 13

Slide 13 text

Prototypal Inheritance Warning: Here be dragons…at first.

Slide 14

Slide 14 text

Object Methods Via the Prototype function Car(make, model, year) { this.make = make; this.model = model; this.year = year; this.toString = function() { return this.year + " " + this.make + " " + this.model; } }

Slide 15

Slide 15 text

Object Methods Via the Prototype function Car(make, model, year) { this.make = make; this.model = model; this.year = year; this.toString = function() { return this.year + " " + this.make + " " + this.model; } } function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } Car.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; }

Slide 16

Slide 16 text

function Car(make, model, year) { this.make = make; this.model = model; this.year = year; this.toString = function() { return this.year + " " + this.make + " " + this.model; } } var aCar = new Car('Saturn', 'Vue', 2007); var anotherCar = new Car('Ford', 'F150', '2003'); aCar.toString(); // '2007 Saturn Vue' anotherCar.toString(); // '2003 Ford F150' aCar.toString = function() { return '2013 BMW 335is Convertible'; }; aCar.toString(); // '2013 BMW 335is Convertible' anotherCar.toString(); // '2003 Ford F150'

Slide 17

Slide 17 text

function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } Car.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } var aCar = new Car('Saturn', 'Vue', 2007); var anotherCar = new Car('Ford', 'F150', '2003'); aCar.toString(); // '2007 Saturn Vue' anotherCar.toString(); // '2003 Ford F150' Car.prototype.toString = function() { return '2013 BMW 335is Convertible'; }; aCar.toString(); // '2013 BMW 335is Convertible' anotherCar.toString(); // '2013 BMW 335is Convertible'

Slide 18

Slide 18 text

class Dad extends Person { public function __construct($firstName) { $this->familyName = 'Carouth'; parent::__construct($firstName); } } class Son extends Dad { } $son = new Son('Jeff'); print $son->familyName; // 'Carouth'

Slide 19

Slide 19 text

var Dad = function() { this.familyName = 'Carouth'; }; var Son = function(firstName) { this.firstName = firstName; }; Son.prototype = new Dad(); Son.prototype.constructor = Son; var jeff = new Son('Jeff'); jeff.familyName; // 'Carouth' jeff instanceof Son; // true jeff instanceof Dad; // true

Slide 20

Slide 20 text

Namespaces Easy in PHP 5.3+ Easy enough in JavaScript

Slide 21

Slide 21 text

Slide 22

Slide 22 text

var Foo = Foo || {}; Foo.Car = function(make, model, year) { // ...snip.. }; var myCar = new Foo.Car('Toyota', 'Prius', '2011');

Slide 23

Slide 23 text

The Module Pattern

Slide 24

Slide 24 text

var Car = (function() { var Constructor; Constructor = function(make, model, year) { this.make = make; this.model = model; this.year = year; } Constructor.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } return Constructor; }());

Slide 25

Slide 25 text

var Car = (function() { var Constructor; Constructor = function(make, model, year) { this.make = make; this.model = model; this.year = year; } Constructor.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } return Constructor; }()); (function() { }());

Slide 26

Slide 26 text

var Car = (function() { var Constructor; Constructor = function(make, model, year) { this.make = make; this.model = model; this.year = year; } Constructor.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } return Constructor; }()); var Car = var Constructor; return Constructor;

Slide 27

Slide 27 text

var Car = (function($) { var Constructor; Constructor = function(make, model, year) { this.make = make; this.model = model; this.year = year; } Constructor.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } return Constructor; }(jQuery)); Dependencies

Slide 28

Slide 28 text

Extension myCar.beep(); //undefined Car = (function(Car) { Car.prototype.beep = function() { return 'Beep'; }; return Car; }(Car)); myCar.beep(); // 'Beep'

Slide 29

Slide 29 text

Information Hiding A.K.A. private properties

Slide 30

Slide 30 text

var Car = (function() { var started = false; var Constructor; Constructor = function(make, model, year) { /* snip */ }; Constructor.prototype = { constructor: Constructor, toString: function() { /* snip */ }, start: function() { if (!started) { started = true; } }, isRunning: function() { return started === true; } }; return Constructor; })();

Slide 31

Slide 31 text

var myCar = new Car('BMW', '335is Convertible', 2013); myCar.isRunning(); // false myCar.started; // undefined myCar.start(); myCar.isRunning(); // true

Slide 32

Slide 32 text

require.js file and module loader

Slide 33

Slide 33 text

Example Application

My Example Application

Slide 34

Slide 34 text

require(["jquery", "Car"], function($, Car) { var myCar = new Car('BMW', '335is Convertible', 2013); $("#output").html(myCar.toString()); }); scripts/main.js

Slide 35

Slide 35 text

scripts/Car.js define(function () { var Constructor; Constructor = function(make, model, year) { this.make = make; this.model = model; this.year = year; }; Constructor.prototype.toString = function() { return this.year + " " + this.make + " " + this.model; } return Constructor; });

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

“MV*” Frameworks Backbone.js, KnockoutJS, AngularJS

Slide 38

Slide 38 text

structure with models, collections, and views simple binding and handling of events connection to RESTful JSON API

Slide 39

Slide 39 text

View Presenter Model Backbone.Model Backbone.Collection Templates Underscore.js Backbone.View Backbone.Router Backbone.Events Backbone.Sync

Slide 40

Slide 40 text

Backbone.Router Binds URLs and hashes to routes.

Slide 41

Slide 41 text

Backbone.Router MyRouter = Backbone.Router.extend({ routes: { "": "index", "cars": "cars", "cars/:id": "car" }, index: function() { /* show homepage */ }, cars: function() { /* list of cars */ }, car: function(id) { /* show car */ } });

Slide 42

Slide 42 text

Backbone.View View takes data and transform it into HTML via templates and a reference to a DOM element. The view also listens to events and triggers action based those events.

Slide 43

Slide 43 text

Backbone.View var CarView = Backbone.View.extend({ tagName: "li", className: "car", events: { 'click .start': 'start' }, render: function() { this.$el.html( this.name() + ' [start]' ); return this; }, start: function() { alert('car started'); }, name: function() { return this.model.toString(); } });

Slide 44

Slide 44 text

Backbone.Model The model syncs with a server. If the backend is RESTful the “out of the box” sync will just work. A model holds information about a single record from the backend. Model update triggers and event which will update the view for that specific model.

Slide 45

Slide 45 text

Backbone.Model var Car = Backbone.Model.extend({ urlRoot: '/cars', toString: function() { return this.get('year') + " " + this.get('make') + " " + this.get('model'); } }); var CarView = Backbone.View.extend({ initialize: function() { this.model.on('change', this.render, this); } /* ...snip... */ });

Slide 46

Slide 46 text

Backbone.Collection An “array” of models. Can also sync to the server if given a url root.

Slide 47

Slide 47 text

Backbone.Collection var Cars = Backbone.Collection.extend({ url: '/cars', model: Car }); var CarsView = Backbone.View.extend({ initialize: function() { this.collection = new Cars(); this.collection.fetch({ success: _.bind(function(resp, status, xhr) { this.render(); }, this) }); }, render: function() { this.collection.each(this.renderCar, this); }, renderCar: function(model) { var carView = new CarView({model: model}); this.$el.append(carView.el); } });

Slide 48

Slide 48 text

Templates in Backbone There is no default. You can use Underscore.js templates since it is a dependency. You are able to use whatever JavaScript templating such as Handlebars.

Slide 49

Slide 49 text

QUnit You do test your code, don’t you?

Slide 50

Slide 50 text

Example Test Runner

Slide 51

Slide 51 text

(function() { QUnit.config.autostart = false; require.config({ baseUrl: "../src" }); var testModules = [ "model/CarTests.js" ]; require(testModules, QUnit.start); }());

Slide 52

Slide 52 text

define(function(require) { var Car = require("./Car"); QUnit.module("model/Car", { setup: function() {}, teardown: function() {} }); QUnit.test("Car should not be running when first created", function() { var mycar = new Car('BMW', '335is', 2013); ok(!mycar.isRunning()); } ); QUnit.test("Car should be running after it is started", function() { var mycar = new Car("BMW", "335is", 2013); mycar.start(); ok(mycar.isRunning()); } ); });

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

Grunt Task-based build tool for JavaScript projects.

Slide 55

Slide 55 text

module.exports = function(grunt) { grunt.initConfig({ lint: { src: ['src/model/**/*.js'], tests: ['tests/model/**/*.js'] }, qunit: { files: ['tests/tests.html'] }, uglify: {} }); grunt.registerTask('default', 'lint qunit'); };

Slide 56

Slide 56 text

$ grunt Running "lint:src" (lint) task Lint free. Running "lint:tests" (lint) task Lint free. Running "qunit:files" (qunit) task Testing tests.htmlOK >> 2 assertions passed (15ms) Done, without errors.

Slide 57

Slide 57 text

Thank You! https://joind.in/7022 @jcarouth | [email protected] http://speakerdeck.com/jcarouth