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.

0f930e13633535c1c4041e95b8881308?s=128

Jeff Carouth

May 21, 2014
Tweet

Transcript

  1. reducing the wat-factor of JS JavaScript’s Difficult Concepts Explained PRESENTED

    BY JEFF CAROUTH @jcarouth
  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()";! }
  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()
  15. foo = "I am a globally-scoped var.";! ! function sayFoo()

    {! console.log(foo);! }! ! function defineFoo() {! var foo = "I am set in defineFoo()";! }
  16. foo = ! function console.log(foo);! } ! function var foo

    = } var
  17. 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.
  18. count = 25;! ! function countOccurrences(num) {! num = num

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

    || 1;! count += num;! }! ! countOccurrences(1);! // > count = 26!
  20. // …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();!
  21. // …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!
  22. function console.log(vals }! count = vals.length;

  23. // …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!
  24. Avoid using global variables inside function scope by declaring them

    with the var keyword. Takeaway #1
  25. 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]);! }! }!
  26. Context 2.

  27. this PLEASE EXPLAIN

  28. <?php! ! class Counter! {! private $counter;! ! public function

    increaseCount()! {! $this->counter++;! }! }!
  29. magicCounter = {! count: 0,! increaseCount: function() {! this.count++;! },!

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

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

    decreaseCount: function() {! this.count--;! }! };! ! console.log(magicCounter.count); // 0! magicCounter.increaseCount();! console.log(magicCounter.count); // 1!
  32. 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! !
  33. 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!
  34. magicCounter.count = 0;! ! myCounterIncreaser = function(callback) {! console.log("Increasing counter.");!

    callback();! console.log(magicCounter.count);! console.log(this.count);! }!
  35. 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!
  36. 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!
  37. The this keyword and the context within the function depend

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  54. {}

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

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

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

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

    $name;! }! ! public function sayHello()! {! return "Hello. My name is {$this->name}.";! }! }
  59. <?php! class Developer extends Person! {! public function __construct($name) {!

    parent::__construct($name);! }! ! public function sayHello()! {! return parent::sayHello() . " I am a developer.";! }! }!
  60. function Person(name) {! this.name = name;! }! ! Person.prototype.sayHello =

    function() {! return "Hello. My name is " + this.name + ".";! }
  61. Tip Use Function.prototype to add methods to your constructor functions

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

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

    Person! Developer.prototype = Object.create(Person.prototype);!
  64. 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;!
  65. 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.";! }!
  66. var p = new Person('PersonGuy');! var d = new Developer('DeveloperGal');!

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

    ! console.log(p.sayHello());! // > Hello. My name is PersonGuy.!
  68. 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.!
  69. 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!
  70. 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!
  71. 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!
  72. 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!
  73. Tip For more information on OOP JS, visit the Mozilla

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

    prototype. Takeaway #5
  75. Resources 4.

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

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

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

  79. 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.
  80. JEFF CAROUTH DEVELOPER AT LIFTOPIA @jcarouth jcarouth@gmail.com Freenode: #phpmentoring 50%

    of Loosely Coupled
  81. Thank You joind.in/10647 @jcarouth