ZendCon 2013 - JavaScript's Difficult Concepts

ZendCon 2013 - JavaScript's Difficult Concepts

When approaching JavaScript as a PHP developer some of the nuances of the language take a while to become comfortable.

If you've ever wondered how context and the this keyword work, when to declare a variable, how to create objects and use prototypes in JavaScript, you are not alone. These concepts seems crazy at first, but with some examples you can grasp and use them in your code today.

This session will cover the finer points of JavaScript the language from the perspective of someone who is proficient with PHP or another language.

0f930e13633535c1c4041e95b8881308?s=128

Jeff Carouth

October 09, 2013
Tweet

Transcript

  1. reducing the wat-factor when PHPers write JS JavaScript’s Difficult Concepts

    Explained Jeff Carouth // @jcarouth // #zendcon
  2. None
  3. Wat? 0.

  4. var_dump([] + []);

  5. var_dump([] + []); // => []

  6. console.dir([] + []);

  7. console.dir([] + []); // => ''

  8. WAT? https://www.destroyallsoftware.com/talks/wat

  9. Scope 1.

  10. global& function

  11. foo = "I am a globally-scoped var."; console.log(foo); // >

    I am a globally-scoped var.
  12. foo = "I am a globally-scoped var."; function sayFoo() {

    console.log(foo); } sayFoo(); // > I am a globally-scoped var.
  13. foo = "I am a globally-scoped var."; function sayFoo() {

    console.log(foo); } function defineFoo() { foo = "I am set in defineFoo()"; } defineFoo(); sayFoo(); // > I am set in defineFoo()
  14. count = 25; function countOccurrences(num) { num = num ||

    1; count += num; } function doSomethingInnocent() { var vals = [1, 2, 3, 4]; for (i = 0, count = vals.length; i < count; i++) { console.log(vals[i]); } } countOccurrences(1); // > count = 26 doSomethingInnocent(); // > count = 4
  15. foo = "I am a globally-scoped var."; function sayFoo() {

    console.log(foo); } function defineFoo() { var foo = "I am set in defineFoo()"; } defineFoo(); sayFoo(); // > I am a globally-scoped var.
  16. Avoid using global variables inside function scope by declaring them

    with the var keyword. Takeaway #1
  17. Tip Declare all variables at the top of your function.

    function myFunction(input) { var i, count; for (i = 0, count = input.length; i < count; i++) { console.log(input[i]); } }
  18. Context 2.

  19. this PLEASE EXPLAIN

  20. <?php class Example { private $counter; private $closed; public function

    doSomethingMagic() { $this->counter = 5; $this->doSomethingElse(); } public function doSomethingElse() { // do something } }
  21. magicCounter = { count: 0, increaseCount: function() { this.count++; },

    decreaseCount: function() { this.count--; } }; console.log(magicCounter.count); // 0 magicCounter.increaseCount(); magicCounter.increaseCount(); console.log(magicCounter.count); // 2 magicCounter.decreaseCount(); console.log(magicCounter.count); // 1
  22. count = 0; magicCounter.count = 0; myCounterIncreaser = function(callback) {

    console.log("Increasing counter."); callback(); callback(); console.log(magicCounter.count); // 0 console.log(this.count); // 2 } myCounterIncreaser(magicCounter.increaseCount); // > Increasing counter. // > 0 // > 2
  23. The this keyword and the context of the function depend

    entirely on how the function was invoked. Takeaway #2
  24. default context

  25. None
  26. function logContext() { console.log(this); } logContext(); // > Global

  27. function contextMagic() { function logContext() { console.log(this); } logContext(); }

    contextMagic(); // > Global
  28. The default context will be the global context for functions

    invoked by name or variable name within the global context. Takeaway #3
  29. method context

  30. contextMethod = { logContext: function() { console.log(this); } }; contextMethod.logContext();

    // > Object { logContext: [Function] }
  31. contextMethod = { logContext: function() { console.log(this); } }; contextMethod.logContext();

    // > Object { logContext: [Function] } var myContextLogger = contextMethod.logContext; myContextLogger(); // > Global
  32. .call() & .apply()

  33. var foo = { logContext: function() { console.log(this); } };

    foo.logContext(); // > Object { logContext: [Function] } foo.logContext.call(this); // > Global
  34. var foo = { logContext: function() { console.log(this); } };

    var bar = { baz: "fizz" }; foo.logContext(); // > Object { logContext: [Function] } foo.logContext.call(bar); // > Object { baz: "fizz" }
  35. Using .call() and .apply() gives you the control you might

    need over the context inside a function or method. Takeaway #4
  36. Objects & Prototypes 3.

  37. {}

  38. var foo = { bar: "baz", fizz: "buzz", bang: function()

    { console.log(this.bar + " " + this.fizz); } }; foo.bang(); // > baz buzz
  39. prototype chain JavaScript’s complicated inheritance model Object Oriented JavaScript and

    the
  40. <?php class Person { public function __construct($name) { $this->name =

    $name; } public function sayHello() { return "Hello. My name is {$this->name}."; } } class Developer extends Person { public function __construct($name) { parent::__construct($name); } public function sayHello() { return parent::sayHello() . " I am a developer."; } }
  41. function Person(name) { this.name = name; } Person.prototype.sayHello = function()

    { return "Hello. My name is " + this.name + "."; }
  42. Tip Use Function.prototype to add methods to your constructor functions

    for performance reasons.
  43. function Person(name) { this.name = name; } Person.prototype.sayHello = function()

    { return "Hello. My name is " + this.name + "."; } function Developer(name) { Person.call(this, name); }
  44. function Developer() { Person.call(this); } // inherit from Person Developer.prototype

    = Object.create(Person.prototype);
  45. function Developer(name) { Person.call(this, name); } // inherit from Person

    Developer.prototype = Object.create(Person.prototype);
  46. function Developer(name) { Person.call(this, name); } // inherit from Person

    Developer.prototype = Object.create(Person.prototype); // correct the prototype constructor from Person to Developer Developer.prototype.constructor = Developer;
  47. function Developer(name) { Person.call(this, name); } // inherit from Person

    Developer.prototype = Object.create(Person.prototype); // correct the prototype constructor from Person to Developer Developer.prototype.constructor = Developer; // override the sayHello method of Person for Developers Developer.prototype.sayHello = function() { return Person.prototype.sayHello.call(this) + " I am a developer."; }
  48. var p = new Person('PersonGuy'); var d = new Developer('DeveloperGal');

  49. var p = new Person('PersonGuy'); var d = new Developer('DeveloperGal');

    console.log(p.sayHello()); // > Hello. My name is PersonGuy. console.log(d.sayHello()); // > Hello. My name is DeveloperGal. I am a developer.
  50. var p = new Person('PersonGuy'); var d = new Developer('DeveloperGal');

    console.log(p.sayHello()); // > Hello. My name is PersonGuy. console.log(d.sayHello()); // > Hello. My name is DeveloperGal. I am a developer. console.log(p instanceof Person); // > true console.log(p instanceof Developer); // > false
  51. var p = new Person('PersonGuy'); var d = new Developer('DeveloperGal');

    console.log(p.sayHello()); // > Hello. My name is PersonGuy. console.log(d.sayHello()); // > Hello. My name is DeveloperGal. I am a developer. console.log(p instanceof Person); // > true console.log(p instanceof Developer); // > false console.log(d instanceof Developer); // > true console.log(d instanceof Person); // > true
  52. Tip For more information on OOP JS, visit the Mozilla

    Developer Zone article at http://crth.net/mdnoopjs
  53. Object oriented development in JavaScript requires an understanding of the

    prototype. Takeaway #5
  54. Resources 4.

  55. JavaScript Essential Reading List http://crth.net/jsreading WatchMeCode.net JavaScript Fundamentals http://crth.net/jsfundamentals

  56. Recap 5. All Objects have a prototype through which we

    can accomplish inheritance in JS. 1. Avoid using global vars inside function scope. 2. Context and this depend on invocation. 3. Default context is the global context. 4. .call() and .apply() gives you control over the context.
  57. JEFF CAROUTH DEVELOPER AT LIFTOPIA @jcarouth jcarouth@gmail.com Freenode: #phpmentoring

  58. Thanks. http://speakerdeck.com/jcarouth Q&A http://joind.in/9339 Jeff Carouth // @jcarouth // #zendcon