$30 off During Our Annual Pro Sale. View Details »

JavaScript's Difficult Concepts Explained

JavaScript's Difficult Concepts Explained

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. - See more at: http://midwestphp.org/sessions/JavaScript's_Difficult_Concepts_Explained#sthash.nKUpmxaT.dpuf

Jeff Carouth

March 02, 2013
Tweet

More Decks by Jeff Carouth

Other Decks in Programming

Transcript

  1. reducing the wat-factor when PHPers write JS
    JavaScript’s Difficult
    Concepts Explained
    Jeff Carouth // @jcarouth // #midwestphp

    View Slide

  2. JEFF CAROUTH
    DEVELOPER AT LIFTOPIA
    @jcarouth

    View Slide

  3. View Slide

  4. View Slide

  5. Wat?
    0.

    View Slide

  6. php
    var_dump(array() + array());
    javascript
    console.dir([] + []);

    View Slide

  7. php
    var_dump(array() + array());
    javascript
    console.dir([] + []);
    array(0) {
    }

    View Slide

  8. php
    var_dump(array() + array());
    array(0) {
    }
    javascript
    console.dir([] + []);
    ''
    ''

    View Slide

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

    View Slide

  10. Scope
    1.

    View Slide

  11. global& function

    View Slide

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

    View Slide

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

    View Slide

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

  15. i = 25;
    function countOccurrences(num) {
    num = num || 1;
    i += num;
    }
    function doSomethingInnocent() {
    var vals = [1, 2, 3, 4];
    for (i = 0; i < vals.length; i++) {
    console.log(vals[i]);
    }
    }
    countOccurrences(1);
    // > i = 26
    doSomethingInnocent();
    // > i = 4

    View Slide

  16. 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 Slide

  17. variable hoisting

    View Slide

  18. foo = "I am a globally-scoped var.";
    function sayFoo() {
    console.log(foo);
    }
    function cleverlyDefineFoo() {
    var bar = "I am bar. " + foo;
    console.log(foo);
    var foo = "I am a local foo.";
    }
    cleverlyDefineFoo();
    sayFoo();
    // > I am bar. undefined
    // > undefined
    // > I am a globally-scoped var.

    View Slide

  19. “private variables”

    View Slide

  20. foo = "I am global foo.";
    function myModule() {
    function sayFoo() {
    console.log(foo);
    }
    sayFoo();
    }
    myModule();
    // > I am a global foo.

    View Slide

  21. foo = "I am global foo.";
    function myModule() {
    function sayFoo() {
    var foo;
    foo = "I am a local variable.";
    console.log(foo);
    }
    sayFoo();
    }
    myModule();
    console.log(foo);
    // > I am a local variable.
    // > I am global foo.

    View Slide

  22. function myModule() {
    var foo;
    function sayFoo() {
    foo = "I am a local variable.";
    console.log(foo);
    }
    sayFoo();
    }
    myModule();
    console.log(foo);
    // > I am a local variable.
    // > ReferenceError: foo is not defined

    View Slide

  23. IIFE&Modules

    View Slide

  24. (function() {
    //do something
    })();

    View Slide

  25. (function() {
    var foo;
    function defineFoo() {
    foo = "I am a local variable.";
    }
    defineFoo();
    console.log(foo);
    })();
    // > I am a local variable.

    View Slide

  26. var module = (function() {
    var foo;
    function defineFoo() {
    foo = {
    bar: "I am bar.",
    baz: function() {
    console.log("I am baz.");
    }
    };
    }
    defineFoo();
    return foo;
    })();
    console.log(module.bar);
    // > I am bar.
    module.baz();
    // > I am baz.

    View Slide

  27. var counter = (function() {
    var count = 0;
    return {
    increase: function() {
    count++;
    return count;
    },
    decrease: function() {
    count--;
    return count;
    }
    };
    })();
    console.log(counter.increase()); // 1
    console.log(counter.increase()); // 2
    console.log(counter.increase()); // 3
    console.log(counter.decrease()); // 2
    console.log(counter.increase()); // 3
    console.log(counter.increase()); // 4
    console.log(counter.decrease()); // 3

    View Slide

  28. locally-scoped
    globals

    View Slide

  29. var myModule = (function($, _) {
    return {
    display: function(a) {
    _.each(a, console.log);
    }
    }
    })(jQuery, _);

    View Slide

  30. Context
    2.

    View Slide

  31. this
    PLEASE EXPLAIN

    View Slide

  32. class Example
    {
    private $counter;
    private $closed;
    public function doSomethingMagic()
    {
    $this->counter = 5;
    $this->doSomethingElse();
    }
    public function doSomethingElse()
    {
    // do something
    }
    }

    View Slide

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

    View Slide

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

    View Slide

  35. global& function

    View Slide

  36. function myFoo() {
    var bar = "baz";
    function something() {
    console.log(bar);
    }
    something();
    }
    myFoo();
    // > baz

    View Slide

  37. function myFoo() {
    var bar = "baz";
    this.something = function() {
    console.log(bar);
    }
    this.something();
    }
    myFoo();
    // > baz

    View Slide

  38. function myFoo() {
    var bar = "baz";
    this.something = function() {
    console.log(bar);
    }
    this.something();
    }
    myFoo();
    // > baz
    something();
    // > baz

    View Slide

  39. function Foo() {
    var bar = "baz";
    this.something = function() {
    console.log(bar);
    }
    this.something();
    }
    myFoo = new Foo();
    // > baz
    something();
    // > ReferenceError: something is not defined
    myFoo.something();
    // > baz

    View Slide

  40. default context

    View Slide

  41. View Slide

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

    View Slide

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

    View Slide

  44. method context

    View Slide

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

    View Slide

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

    View Slide

  47. .call() & .apply()

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  52. var fizz = {
    buzz: function() {
    for (var i = this.start; i <= this.end; i++) {
    console.log(i);
    }
    }
    };
    var range = {
    start: 1,
    end: 3
    };
    fizz.buzz.call(range);
    // > 1
    // > 2
    // > 3

    View Slide

  53. var module = {
    printRange: function(start, end) {
    console.log(start + ".." + end);
    }
    };
    var bar = {};
    module.printRange.call(bar, 1, 5);
    // > 1..5
    module.printRange.apply(bar, [3, 25]);
    // > 3..25

    View Slide

  54. Objects &
    Prototypes
    3.

    View Slide

  55. {}

    View Slide

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

    View Slide

  57. functions

    View Slide

  58. var logContext = function() {
    console.log(this);
    };
    console.log(logContext);
    // > [Function]
    console.log(typeof logContext);
    // > function

    View Slide

  59. Classes
    PROTOTYPES

    View Slide

  60. var someFunction = function() {
    console.log(this);
    };
    var obj = new someFunction();
    console.log(obj);
    // > Object [someFunction]
    // > Object [someFunction]

    View Slide

  61. var someFunction = function() {
    console.log(this);
    };
    var obj = new someFunction();
    console.log(obj);
    // > Object [someFunction]
    // > Object [someFunction]
    var SomeFunction = function() {
    console.log(this);
    };
    var obj = new SomeFunction();
    // > Object [SomeFunction]

    View Slide

  62. var Car = function() {
    this.make = "Ford";
    this.model = "F150";
    this.started = false;
    this.start = function() {
    if (this.started) {
    return;
    }
    this.started = true;
    };
    };
    var myCar = new Car();
    console.log(myCar);
    // > { make: 'Ford', model: 'F150', started: false, start: ...
    myCar.start();
    console.log(myCar);
    // > { make: 'Ford', model: 'F150', started: true, start: ...

    View Slide

  63. var Car = function(make, model) {
    this.make = make;
    this.model = model;
    this.toString = function() {
    return this.make + " " + this.model;
    };
    };
    var myCar = new Car("Dodge", "Charger");
    var wifeCar = new Car("Ford", "Edge");
    console.log(myCar.toString());
    // > Dodge Charger
    console.log(wifeCar.toString());
    // > Ford Edge

    View Slide

  64. var Car = function(make, model) {
    this.make = make;
    this.model = model;
    this.toString = function() {
    return this.make + " " + this.model;
    };
    };
    var myCar = new Car("Dodge", "Charger");
    var wifeCar = new Car("Ford", "Edge");
    myCar.toString = function() {
    return this.model + ", " + this.make;
    };
    console.log(myCar.toString());
    // > Charger, Dodge
    console.log(wifeCar.toString());
    // > Ford Edge

    View Slide

  65. var Car = function(make, model) {
    this.make = make;
    this.model = model;
    };
    Car.prototype.toString = function() {
    return "Model:" + this.model + ", Make:" + this.make;
    };
    var myCar = new Car("Dodge", "Charger");
    var wifeCar = new Car("Ford", "Edge");
    console.log(myCar.toString());
    // > Model:Charger, Make:Dodge
    console.log(wifeCar.toString());
    // > Model:Edge, Make:Ford
    Car.prototype.toString = function() {
    return "Model:335i Convertible, Make:BMW";
    }
    console.log(myCar.toString());
    // > Model:335i Convertible, Make:BMW
    console.log(wifeCar.toString());
    // > Model:335i Convertible, Make:BMW

    View Slide

  66. prototype chain

    View Slide

  67. var myPrototype = {
    sayFoo: function() {
    console.log("foo");
    }
    };
    obj = Object.create(myPrototype);
    obj.sayFoo();
    // > foo

    View Slide

  68. grandParent = {
    sayFoo: function() {
    console.log("foo");
    }
    };
    myPrototype = Object.create(grandParent);
    obj = Object.create(myPrototype);
    obj.sayFoo();
    // > foo

    View Slide

  69. grandParent = {
    sayFoo: function() {
    console.log("foo");
    }
    };
    myPrototype = Object.create(grandParent);
    myPrototype.bar = "I am set in myPrototype.";
    obj = Object.create(myPrototype);
    obj.sayFoo();
    // > foo
    console.log(obj.bar);
    // > I am set in myPrototype.

    View Slide

  70. grandParent = {
    sayFoo: function() {
    console.log("foo");
    }
    };
    myPrototype = Object.create(grandParent);
    myPrototype.bar = "I am set in myPrototype.";
    obj = Object.create(myPrototype);
    obj.sayFoo();
    // > foo
    console.log(obj.bar);
    // > I am set in myPrototype.
    obj.bar = "I am overriding the myPrototype.bar property.";
    console.log(obj.bar);
    // > I am overriding the myPrototype.bar property.

    View Slide

  71. grandParent = {
    sayFoo: function() {
    console.log("foo");
    }
    };
    myPrototype = Object.create(grandParent);
    myPrototype.bar = "I am set in myPrototype.";
    obj = Object.create(myPrototype);
    obj.sayFoo();
    // > foo
    console.log(obj.bar);
    // > I am set in myPrototype.
    obj.bar = "I am overriding the myPrototype.bar property.";
    console.log(obj.bar);
    // > I am overriding the myPrototype.bar property.
    console.log(myPrototype.bar);
    // > I am set in myPrototype.

    View Slide

  72. Resources
    4.

    View Slide

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

    View Slide

  74. Thanks.
    http://speakerdeck.com/jcarouth
    Q&A
    http://joind.in/8210

    View Slide