javascript fundamentals for php developers
DESCRIPTION
Javascript fundamentals from a PHP developers' point of view. Compares some of the principles of javascript with their php counterpart. Introduces a way to build simple robust modules in Javascript. You can view the source of the slides (html+js) here: https://bitbucket.org/chrisramakers/talk-javascript-for-php-developersTRANSCRIPT
JAVASCRIPT FUNDAMENTALSFOR PHP DEVELOPERS
@chrisramakersNovember 2013 PHPBenelux Usergroup Meeting
WHO AM I?@chrisramakersZend Certified PHP EngineerSoftware Engineer @ NucleusFront- and backend developmentBuilding RESTFUL API'sIntegrating them with AngularJS
WHAT ABOUT YOU?Never used JavascriptIntermediate JavascriptJavascript expert
WHAT IS THIS TALK ABOUT?I can hear you "I know Javascript! Booooring!"
I'm not a guru either but I have a lot of experience.So I'm going to share some of it with you.
HistoryJavascript BootcampWriting modulesWhat will the future bring?
JAVASCRIPT HISTORY
JAVASCRIPT HISTORYInterpreted scripting languageObject oriented but not Class basedMost popular language on GithubDeveloped at Netscape in 1995Around the same time as PHP (1997)First called LiveScript, then renamed JavascriptStandardised as ECMAScript (ECMA-262) in 1997Other implementations
Serverside: Netscape Enterprise Server, Node.JS,Databases: CouchDB, MongoDB, Riak, ...CoffeescriptAdobe: ExtendScript, Actionscript,
IT'S EVEN A POWERPOINT REPLACEMENT!These slides are built with reveal.js
Check it out: lab.hakim.se/reveal-js
WE KNEW JAVASCRIPT LIKE THIS
Note: This is a screenshot, not a real error!!! :D
AND THIS
SIGH
BUT WE COULD DO STUFF LIKE THIS TOOfunction trollolololl() { window.open(self.location, '');}window.onload = trollolololl;
And feel like a real hacker :)note: this no longer works
HOW WE KNOW JAVASCRIPTA lot has changed, there are many high quality libraries and tools available.
But we are not going to talk about that ...
JAVASCRIPT BOOTCAMP!
OPERATORSTHE BASIC BUNCH
Assignment operators = += -= *= ...Arithmic operators + - / *Bitwise operators >> << & ̂ | ~Comparison operators == != === !== > >= < <=Logical operators || && !
Look familiar no?
OPERATORS CONTINUED ...concatoperator +
concatenates 2 strings
in -operator determines if the left operant is a property of the rightoperant
delete removes a property from an object
typeof returns the data type of an object
instanceof determines of the left operant is of the the right operantobject type
And more like new, this, ...Again most of these should look familiar.
DATA TYPES PHP JavascriptPrimitives string
integerfloatboolean
StringNumberBoolean
Compound arrayobject
ArrayObject
Special resourcenull
undefinednull
THE GLOBAL OBJECTSomething like $GLOBALS inphpAccessible everywherewindow-object in browsers
3 GLOBAL PROPERTIESNaNInfinityundefined
9 GLOBAL FUNCTIONSJavascript PHPparseInt() intval()parseFloat() floatval()isNaN() is_nan()isFinite() is_finite()encodeURIComponent() urlencode()decodeURIComponent() urldecode()encodeURI() ??decodeURI() ??eval() eval()
9 GLOBAL CONSTRUCTORSNot the same as constructors in PHP
String()Number()Boolean()Array()Object()Error()RegExp()Date()Function()
IMMUTABLEAll constructors are immutable Objects
String.prototype.append = function(val){ this = this + val;}
var a = 'Foo';var b = a.append('Bar');
ReferenceError: Invalid left-hand side in assignment
LITERALS AND CONSTRUCTORSWe don't need constructors ... we got literals!
Literal Constructor
String "Nucleus" new String("Nucleus");
Boolean true new Boolean(true);
Array ['a', 'a']; new Array('a', 'b');
Objects { a : 'b' } new Object();
Number 1.23; new Number(1.23);
RegExp /[A-Z]/i; new RegExp('[A-Z]', 'i');
Function function(x){ return x+1; }; new Function('x', 'return x+1;');
Date There is no Date literal new Date(2013, 11, 23);
RELATION BETWEEN LITERALS AND CONSTRUCTORSvar a = "foobar";var b = a.toUpperCase();alert(b); // Alerts "FOOBAR"
Constructors wrap literals internallyJavascript internally converts primitives to their object counterpartCauses some really funky behaviour!WTFPM++
AND NOW THE "FUN" BEGINS ...TYPEOF
typeof 'foo'; // "string"
typeof String; // "function"
typeof String(); // "string"
var s = new String('foo');typeof s // "object"
INSTANCEOFvar foo = new String('foo');var bar = 'bar';
foo instanceof String; // truebar instanceof String; // false
Wait ... it gets better :)
var boys = new Array('Joe', 'Bob');var girls = ['Jane', 'Alice'];
boys instanceof Array; // truegirls instanceof Array; // true
instanceof on navite data types is not reliable!use jQuery.type(), angular.isString(), ...
ERRORS AND ERROR HANDLINGPHP Javascript
try { ... } catch(e) { ... } try { ... } catch(e) { ... }
throw new Exception(msg, code); throw 'Something went wrong!';
throw 500;
throw 'up';
throw {message: 'foo', code: 500};
throw new Error('up');
SCOPEScope refers to where a variable or functions are accessible
and in what context they are being manipulated.
There 2 types of scope
GlobalLocal
Basically it means it's attached to the window object which is the topmostobject.
GLOBAL SCOPEWhen something is in the global scope
it means that it is accessible from anywhere in your code.
var foo = "Nucleus";function bar(){ alert(foo);}
bar(); // alerts 'Nucleus'alert(foo) // also alerts 'Nucleus'alert(window.foo) // again alerts 'Nucleus'
LOCAL SCOPEWhen something is in the local scope it means it's only available in the
containing function and all functions defined at the same level or deeper.
function bar(){ var foo = "Nucleus"; alert(foo);}
bar(); // alerts 'Nucleus'alert(foo) // error: foo is not definedalert(window.foo) // error: foo is not defined
CLOSURESA closure is an expression (typically a function) that can have
variables together with an environment that binds those variables(that "closes" the expression).
PHP CLOSURESIn PHP closures are most commonly called 'anonymous functions' and are
implemented using the Closure class.
// PHP Closure$foo = function() { return 'Nucleus';};echo $foo(); // outputs 'Nucleus'echo get_class($foo); // outputs 'Closure'
PHP CLOSURES AND SCOPE$foo = 'Nucleus';$bar = function() { return $foo;};echo $bar(); // PHP Notice: Undefined variable $foo
We need the 'use' construct.
$foo = 'Nucleus';$bar = function() use ($foo) { // added 'use' construct return $foo;};echo $foo(); // Outputs 'Nucleus'
JAVASCRIPT CLOSURESWhenever you see a function, wrapped within another function, a closure is
created and the inner function has access to all variables defined in the outerfunction.
JAVASCRIPT CLOSURES
Outside the greet() function, there is no way to access the prefixvariable.
Only functions defined within the greet() function have access to thisvariable, same goes for the who argument which is also contained within the
closure.
// outer functionfunction greet(who) { var prefix = 'Welcome at '; // Inner function function output(suffix) { alert(prefix + who + suffix); }; output('!');}greet('Nucleus'); // Alerts 'Welcome at Nucleus!'
CLOSURES IN JAVASCRIPTNow we can modify the code to return the inner function.
function greet(who) { var prefix = 'Hello '; var f = function(suffix) { alert(prefix + who + suffix); }; return f;}var joeGreeter = greet('joe');joeGreeter('?'); // Alerts 'Hello joe?'joeGreeter.prefix; // undefined
This way we receive an executable function from the greet() call, but we still have no way to modify the value of prefix.
Looks a lot like private variables in PHP
CLOSURES IN JAVASCRIPTLets add an accessor and mutator (getter and setter).
function greet(who) { var prefix = 'Hello '; var f = function(suffix) { alert(prefix + who + suffix); }; f.setPrefix = function(p){ prefix = p; } f.getPrefix = function(){ return prefix; } return f;}var joeGreeter = greet('joe');joeGreeter('?'); // Alerts 'Hello joe?'
joeGreeter.setPrefix('Hey '); // joe is deaf ...joeGreeter('!!!'); // Alerts 'Hey joe!!!'
SELF EXECUTING FUNCTION PATTERN(function() { // ...}());
Also called IIFE or Immediately Invoked Function ExpressionCreates it's own isolated scope without polluting the global scope.Allows us to 'import' variables into the closure without addressing themglobally
(function($, Y) { // ...}(jQuery, YAHOO));
WRITING JAVASCRIPT MODULESLets do something usefull with it now ...
Javascript doesn't know the concept classes (yet)Nor does it have private/public access to propertiesHow do we build a robust module in javascript then?
HELLO DESIGN PATTERNS!Self Executing Function patternModule pattern
LETS BUILD A SIMPLE MODULE
var COUNTER = (function(){ }());
We start with a self-executingfunction to create an isolate scope.
console.log(COUNTER); // undefined
var COUNTER = (function(){ var _counter = 0; var public = {}; return public;}());
BUILDING A MODULENow we have to actually return
something from our self-executingfunction so COUNTER is not
undefined
console.log(COUNTER); // Object {}
var COUNTER = (function(){ var _counter = 0; var public = { increment : function(){ _counter++; }, getValue : function(){ return _counter; } }; return public;}());
BUILDING A MODULEIf we now add some functions topublic, we create a closure inside
the self-executing function.
console.log(COUNTER.geValue()); // 0 COUNTER.increment();console.log(COUNTER.geValue()); // 1console.log(COUNTER._counter); // undefined
var COUNTER = (function(){ var _counter = 0; var format = function(value){ return 'Counter is ' + value; } var public = { increment : function(){ _counter++; }, getValue : function(){ return format(_counter); } }; return public;}());
BUILDING A MODULENow lets add a "private" method to
format the output a little
COUNTER.increment();COUNTER.increment();
console.log(COUNTER.geValue()); // Counter is 2
var COUNTER = (function(){ var _counter = 0; var _format = 'Counter is '; var format = function(value){ return _format + value; } var public = { increment : function(){ _counter++; }, getValue : function(){ return format(_counter); }, setFormat: function(str){ _format = str; } }; return public;}());
BUILDING A MODULEBut we also want to change the
output format of the module. Lets adda "private" property and a "setter".
COUNTER.increment();COUNTER.increment();
console.log(COUNTER.geValue()); // Counter is 2
COUNTER.setFormat('Value = ');console.log(COUNTER.geValue()); // Value = 2
COUNTER._format = "Foobar"console.log(COUNTER.geValue()); // Value = 2
var COUNTER = (function(){ var _container, _counter = 0, _format = 'Counter is '; var format = function(value){ return _format + value; } var public = { // snip... }; var init = function(container){ _container = container; _container.innerHTML = 'Counter ready!'; return public; } return init;}());
BUILDING A MODULENow we want to configure the
module from the outside. The easiestway to that is to add an init
function.
DEMO TIME ...
<div id="container"></div><button id="trigger">Add 1</button>
var c = document.getElementById('container') t = document.getElementById('trigger');
var myCounter = COUNTER(c);t.onclick = function(){ myCounter.increment();};
Counter ready!Add 1
Try it yourself at http://ncl.uz/counterdemo
A LITTLE EXTRA ...What if we need to build a really large module?Spread over several files?
MODULE AUGMENTATION
// module.jsvar COUNTER = (function(){ var _counter = 0; var _format = 'Counter : '; var format = function(value){ return _format + value; } var public = { increment : function(){ _counter++; }, getValue : function(){ return format(_counter); }, setFormat: function(str){ _format = str; } }; return public;}());
AUGMENTING A MODULEWe want to add a new public methodshout to the already existing
COUNTER
// module.shout.jsvar COUNTER = (function(public){ public.shout = function(){ var output = public.getValue(); return output.toUpperCase(); }; return public;}(COUNTER));
Can only access/override the publicAPI
THE BAD PARTS ...Only one instanceNo inheritance systemAugmentation only has access to the public API
THE FUTUREUMD (UNIVERSAL MODULE DEFINITION)
Defines a way to structure modules so they work both in the browser and on the server
github.com/umdjs/umd
AMD (ASYNCHRONOUS MODULE DEFINITION)
Defines a way to load modules in any arbitrary ordergithub.com/amdjs/amdjs-api
TAKING A LOOK AT ECMASCRIPT 6WHAT CAN WE EXPECT FROM ES6?
Current status: kangax.github.io/es5-compat-table/es6
DEFAULT PARAMETERSES5
function increment(x, y) { y = y || 1; return x += y; }
ES6function increment(x, y = 1) { return x += y; }
LEXICAL SCOPE WITH LETES5
function doSomething() { var x = 5; if (someCondition) { var x = 10; doSomethingElse(x); } console.log(x); // 10 !!}
ES6function doSomething() { let x = 5; if (someCondition) { let x = 10; doSomethingElse(x); } console.log(x); // 5 !!}
CONSTANTSES5
// Nope ... no constants for you
ES6const limit = 100;limit = 200; // SyntaxError
CALLBACK ARROW NOTATIONES5
[1,2,3].map(function (x) { return x * x;});
ES6[1,2,3].map(x => x * x);
CLASS DEFINITIONSES5
function Vehicle(color) { this.color = color; this.speed = 0;} Vehicle.prototype.drive = function() { this.speed = 40;}
ES6class Vehicle { constructor(color) { this.color = color; this.speed = 0; } drive() { this.speed = 40; }}
CLASS INHERITANCEES5
function Car(brand, color) { Vehicle.call(this, color); this.brand = brand; this.wheels = 4;} Car.prototype = Object.create(Vehicle.prototype);Car.prototype.constructor = Car;
ES6class Car extends Vehicle { constructor(brand, color) { super(color); this.brand = brand; this.wheels = 4; }}
WRAPPING UP ...You can build pretty robust modules in JavascriptBut they are still not comparable to PHP ClassesWe haven't touched inheritance, interfaces, abstract classes, etc ...These are all possible with Javascript... but that's for another time
QUESTIONS?
[email protected]@chrisramakersAny feedback is appreciated!joind.in/10254Come talk to me!