Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaScript's Difficult Concepts – php[tek] 2014

JavaScript's Difficult Concepts – php[tek] 2014

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.

Jeff Carouth

May 21, 2014
Tweet

More Decks by Jeff Carouth

Other Decks in Programming

Transcript

  1. reducing the wat-factor of JS
    JavaScript’s Difficult
    Concepts Explained
    PRESENTED BY
    JEFF CAROUTH
    @jcarouth

    View full-size slide

  2. var_dump([] + []);!
    !

    View full-size slide

  3. var_dump([] + []);!
    // => []!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. global& function

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  10. foo = "I am a globally-scoped var.";!
    !
    function sayFoo() {!
    console.log(foo);!
    }!
    !
    function defineFoo() {!
    foo = "I am set in defineFoo()";!
    }

    View full-size slide

  11. 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()

    View full-size slide

  12. foo = "I am a globally-scoped var.";!
    !
    function sayFoo() {!
    console.log(foo);!
    }!
    !
    function defineFoo() {!
    var foo = "I am set in defineFoo()";!
    }

    View full-size slide

  13. foo =
    !
    function
    console.log(foo);!
    }
    !
    function
    var foo =
    }
    var

    View full-size slide

  14. 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.

    View full-size slide

  15. count = 25;!
    !
    function countOccurrences(num) {!
    num = num || 1;!
    count += num;!
    }!

    View full-size slide

  16. count = 25;!
    !
    function countOccurrences(num) {!
    num = num || 1;!
    count += num;!
    }!
    !
    countOccurrences(1);!
    // > count = 26!

    View full-size slide

  17. // …snip…!
    countOccurrences(1);!
    // > count = 26!
    !
    function doSomethingInnocent() {!
    var vals = [1, 2, 3, 4];!
    for (i = 0, count = vals.length; i < count; i++) {!
    console.log(vals[i]);!
    }!
    }!
    doSomethingInnocent();!

    View full-size slide

  18. // …snip…!
    countOccurrences(1);!
    // > count = 26!
    !
    function doSomethingInnocent() {!
    var vals = [1, 2, 3, 4];!
    for (i = 0, count = vals.length; i < count; i++) {!
    console.log(vals[i]);!
    }!
    }!
    doSomethingInnocent();!
    !
    countOccurrences(1);!
    // > count = 5!

    View full-size slide

  19. function
    console.log(vals
    }!
    count = vals.length;

    View full-size slide

  20. // …snip…!
    countOccurrences(1);!
    // > count = 26!
    !
    function doSomethingInnocent() {!
    var vals = [1, 2, 3, 4];!
    for (var i = 0, count = vals.length; i < count; i++) {!
    console.log(vals[i]);!
    }!
    }!
    doSomethingInnocent();!
    !
    countOccurrences(1);!
    // > count = 27!

    View full-size slide

  21. Avoid using global variables inside
    function scope by declaring them
    with the var keyword.
    Takeaway #1

    View full-size slide

  22. 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]);!
    }!
    }!

    View full-size slide

  23. this
    PLEASE EXPLAIN

    View full-size slide

  24. !
    class Counter!
    {!
    private $counter;!
    !
    public function increaseCount()!
    {!
    $this->counter++;!
    }!
    }!

    View full-size slide

  25. magicCounter = {!
    count: 0,!
    increaseCount: function() {!
    this.count++;!
    },!
    decreaseCount: function() {!
    this.count--;!
    }!
    };!

    View full-size slide

  26. magicCounter = {!
    count: 0,!
    increaseCount: function() {!
    this.count++;!
    },!
    decreaseCount: function() {!
    this.count--;!
    }!
    };!
    !
    console.log(magicCounter.count); // 0!

    View full-size slide

  27. magicCounter = {!
    count: 0,!
    increaseCount: function() {!
    this.count++;!
    },!
    decreaseCount: function() {!
    this.count--;!
    }!
    };!
    !
    console.log(magicCounter.count); // 0!
    magicCounter.increaseCount();!
    console.log(magicCounter.count); // 1!

    View full-size slide

  28. magicCounter = {!
    count: 0,!
    increaseCount: function() {!
    this.count++;!
    },!
    decreaseCount: function() {!
    this.count--;!
    }!
    };!
    !
    console.log(magicCounter.count); // 0!
    magicCounter.increaseCount();!
    console.log(magicCounter.count); // 1!
    magicCounter.increaseCount();!
    console.log(magicCounter.count); // 2!
    !

    View full-size slide

  29. magicCounter = {!
    count: 0,!
    increaseCount: function() {!
    this.count++;!
    },!
    decreaseCount: function() {!
    this.count--;!
    }!
    };!
    !
    console.log(magicCounter.count); // 0!
    magicCounter.increaseCount();!
    console.log(magicCounter.count); // 1!
    magicCounter.increaseCount();!
    console.log(magicCounter.count); // 2!
    magicCounter.decreaseCount();!
    console.log(magicCounter.count); // 1!

    View full-size slide

  30. magicCounter.count = 0;!
    !
    myCounterIncreaser = function(callback) {!
    console.log("Increasing counter.");!
    callback();!
    console.log(magicCounter.count);!
    console.log(this.count);!
    }!

    View full-size slide

  31. magicCounter.count = 0;!
    !
    myCounterIncreaser = function(callback) {!
    console.log("Increasing counter.");!
    callback();!
    console.log(magicCounter.count);!
    console.log(this.count);!
    }!
    !
    myCounterIncreaser(magicCounter.increaseCount);!
    // > Increasing counter.!
    // > 0!
    // > 1!

    View full-size slide

  32. magicCounter.count = 0;!
    !
    myCounterIncreaser = function(callback) {!
    console.log("Increasing counter.");!
    callback();!
    console.log(magicCounter.count);!
    console.log(this.count);!
    }!
    !
    myCounterIncreaser(magicCounter.increaseCount);!
    // > Increasing counter.!
    // > 0!
    // > 1!
    myCounterIncreaser(magicCounter.increaseCount);!
    // > Increasing counter.!
    // > 0!
    // > 2!

    View full-size slide

  33. The this keyword and the context
    within the function depend entirely
    on how the function was invoked.
    Takeaway #2

    View full-size slide

  34. default context

    View full-size slide

  35. function logContext() {!
    console.log(this);!
    }!
    !
    logContext();!
    // > Global!

    View full-size slide

  36. function contextMagic() {!
    function logContext() {!
    console.log(this);!
    }!
    !
    logContext();!
    }!
    !
    contextMagic();!
    // > Global!

    View full-size slide

  37. The default context will be the
    global context for functions invoked
    by name or variable name within the
    global context.
    Takeaway #3

    View full-size slide

  38. method context

    View full-size slide

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

    View full-size slide

  40. contextMethod =
    logContext:
    console.log(
    }
    !
    contextMethod.logContext();!
    // > Object { logContext: [Function] }
    var myContextLogger = contextMethod.logContext;!
    myContextLogger();!
    // > Global!

    View full-size slide

  41. .call() & .apply()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. var foo = {!
    logContext: function() {!
    console.log(this);!
    }!
    };!
    !
    var bar = {!
    baz: "fizz"!
    };!

    View full-size slide

  46. var foo = {!
    logContext: function() {!
    console.log(this);!
    }!
    };!
    !
    var bar = {!
    baz: "fizz"!
    };!
    !
    foo.logContext();!
    // > Object { logContext: [Function] } !

    View full-size slide

  47. var foo = {!
    logContext: function() {!
    console.log(this);!
    }!
    };!
    !
    var bar = {!
    baz: "fizz"!
    };!
    !
    foo.logContext();!
    // > Object { logContext: [Function] } !
    !
    foo.logContext.call(bar);!
    // > Object { baz: "fizz" }!

    View full-size slide

  48. Using .call() and .apply()
    gives you the control you might need
    over the context inside a function or
    method.
    Takeaway #4

    View full-size slide

  49. Objects &
    Prototypes
    3.

    View full-size slide

  50. var foo = {!
    bar: "baz",!
    fizz: "buzz",!
    bang: function() {!
    console.log(this.bar + " " + this.fizz);!
    }!
    };!

    View full-size slide

  51. var foo = {!
    bar: "baz",!
    fizz: "buzz",!
    bang: function() {!
    console.log(this.bar + " " + this.fizz);!
    }!
    };!
    !
    foo.bang();!
    // > baz buzz!

    View full-size slide

  52. prototype chain
    JavaScript’s complicated inheritance model
    Object Oriented JavaScript
    and the

    View full-size slide

  53. class Person!
    {!
    public function __construct($name) {!
    $this->name = $name;!
    }!
    !
    public function sayHello()!
    {!
    return "Hello. My name is {$this->name}.";!
    }!
    }

    View full-size slide

  54. class Developer extends Person!
    {!
    public function __construct($name) {!
    parent::__construct($name);!
    }!
    !
    public function sayHello()!
    {!
    return parent::sayHello() . " I am a developer.";!
    }!
    }!

    View full-size slide

  55. function Person(name) {!
    this.name = name;!
    }!
    !
    Person.prototype.sayHello = function() {!
    return "Hello. My name is " + this.name + ".";!
    }

    View full-size slide

  56. Tip
    Use Function.prototype to add methods to your
    constructor functions for performance reasons.

    View full-size slide

  57. function Person(name) {!
    this.name = name;!
    }!
    !
    Person.prototype.sayHello = function() {!
    return "Hello. My name is " + this.name + ".";!
    }!
    !
    function Developer(name) {!
    Person.call(this, name);!
    }!

    View full-size slide

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

    View full-size slide

  59. 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;!

    View full-size slide

  60. 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.";!
    }!

    View full-size slide

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

    View full-size slide

  62. var p = new Person('PersonGuy');!
    var d = new Developer('DeveloperGal');!
    !
    console.log(p.sayHello());!
    // > Hello. My name is PersonGuy.!

    View full-size slide

  63. 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.!

    View full-size slide

  64. 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!

    View full-size slide

  65. 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!

    View full-size slide

  66. 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!

    View full-size slide

  67. 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!

    View full-size slide

  68. Tip
    For more information on OOP JS, visit the

    Mozilla Developer Zone article at

    http://crth.net/mdnoopjs

    View full-size slide

  69. Object oriented development in
    JavaScript requires an understanding
    of the prototype.
    Takeaway #5

    View full-size slide

  70. JavaScript Essential Reading List
    http://crth.net/jsreading

    View full-size slide

  71. WatchMeCode.net JavaScript Fundamentals
    http://crth.net/jsfundamentals

    View full-size slide

  72. https://github.com/getify/You-Dont-Know-JS
    You Don’t Know JS Series

    View full-size slide

  73. 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.

    View full-size slide

  74. JEFF CAROUTH
    DEVELOPER AT LIFTOPIA
    @jcarouth
    [email protected]
    Freenode: #phpmentoring
    50% of Loosely Coupled

    View full-size slide

  75. Thank You
    joind.in/10647
    @jcarouth

    View full-size slide