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. foo = "I am a globally-scoped var.";! ! ! function

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

    {! console.log(foo);! }! ! function defineFoo() {! foo = "I am set in defineFoo()";! }
  3. 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()
  4. foo = "I am a globally-scoped var.";! ! function sayFoo()

    {! console.log(foo);! }! ! function defineFoo() {! var foo = "I am set in defineFoo()";! }
  5. 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.
  6. count = 25;! ! function countOccurrences(num) {! num = num

    || 1;! count += num;! }! ! countOccurrences(1);! // > count = 26!
  7. // …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();!
  8. // …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!
  9. // …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!
  10. 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]);! }! }!
  11. <?php! ! class Counter! {! private $counter;! ! public function

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

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

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

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

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

    entirely on how the function was invoked. Takeaway #2
  21. The default context will be the global context for functions

    invoked by name or variable name within the global context. Takeaway #3
  22. contextMethod = {! logContext: function() {! console.log(this);! }! };! !

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

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

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

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

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

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

    need over the context inside a function or method. Takeaway #4
  29. {}

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

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

    {! console.log(this.bar + " " + this.fizz);! }! };! ! foo.bang();! // > baz buzz!
  32. <?php! class Person! {! public function __construct($name) {! $this->name =

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

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

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

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

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

    ! console.log(p.sayHello());! // > Hello. My name is PersonGuy.!
  40. 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.!
  41. 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!
  42. 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!
  43. 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!
  44. 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!
  45. Tip For more information on OOP JS, visit the Mozilla

    Developer Zone article at http://crth.net/mdnoopjs
  46. 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.