Skip to content

Instantly share code, notes, and snippets.

@piratefsh
Last active May 14, 2022 17:46
Show Gist options
  • Star 36 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save piratefsh/160d94a27aca200dcef8 to your computer and use it in GitHub Desktop.
Save piratefsh/160d94a27aca200dcef8 to your computer and use it in GitHub Desktop.

JavaScript, the weird parts

link to notes https://git.io/vgpKc

about Sher Minn

  • front-end web engineer
  • funemployed, but joining Viki.com in a week
  • recently spent 3 months in NYC at the Recurse Center
    • retreat for programmers
    • where people go to be better at what they do
    • i learned a lot about vanilla JavaScript there
  • i like making art with code

contact

why am i here?

  • i'm not here to bash JavaScript
  • i actually <3 it
  • but it's kinda quirky and easily misunderstood
  • this is about what i wish i knew when i stared learning
  • also, fun facts

how this is run

  • keep it conversational
  • i will introduce a thing, and ask you things
  • feel free to ask questions anytime
  • we can discuss on the go
  • for YOU to get as much understanding

agenda

  • 30m - primer, types, equality, scope
  • 10m - break, q&a
  • 5m - hoisting
  • 10m - the good parts, make friends with JavaScript
  • end, q&a

primer

comfort level check

  • have you written JavaScript?
  • dictionary check
    • callbacks
    • scope
  • had flip table moments with JavaScript?

some history

  • JavaScript != Java
  • back in era of Netscape Navigator (1990s)
  • Netscape decided the web needed to be more dynamic
  • a prototype was written by Brendan Eich in 10 days
  • and was shipped with the next version of Netscape Navigator
    • think about that the next time you ship hacky code
  • ...but it has come a long way since

source

typeof

Let's talk about JavaScript types.

typeof 1    //=> number
typeof 'a'  //=> string
typeof {}   //=> object

typeof []   //=> ???

takeaway

JavaScript has types, and they can be kinda unexpected.


null, undefined, and NaN

null vs undefined

undefined is the default value assigned to a variable that hasn't been assigned one

var foo; // value is undefined

null is used to explicitly say "there is no value here"

var person = {
    name: 'Sher Minn',
    opinionOnJustinBieber: null,
}

person.opinionOnJustinBieber //=> null

What ARE they, though?

typeof null //=> ???
typeof undefined //=> ???

NaN

Stands for 'Not a number'. Used in math operations when result is invalid

Math.sqrt(-1) //=> NaN

Well, guess what type it is?

typeof NaN //=> ???

Let's test for NaN...

NaN == NaN //=> ???

best ways to check for each type

// undefined
typeof foo == 'undefined';

// NaN
isNaN(foo);

// null 
foo === null;

bonus

What happens when you divide by zero in JavaScript?

2/0 

takeaway

In JavaScript, null, undefined and NaN are all different things. treat them with respect.


equality

So you think you know all about equivalence, right?

strict Equality ===

  1 === 1
//=> true. same value.

  1 === '1'
//=> false. different types.

   var a = []
   var b = []
   a === b
//=> false, only true if is same object

   a === a
//=> true, is same object

loose equality ==

Allows you to compare values of different types. Pretty handy, right?

  1 == 1
//=> true

  1 == '1' 
//=> true. the string gets converted into a number.
   var a = []
   var b = []
   a == b
// => false

When comparing two values of same type (e.g. object), JavaScript secretly uses the '===' operator. Which is reasonable.

Type conversion only happens when values are of different types.

it gets a little weird

Then again, type conversion also gives us unexpected results...

   var a = {}
   var b = {}
   
   a == b
// => false

   a == '[object Object]'
// => true

   b == '[object Object]'
// => true

Values of different types get converted into the same type before comparing.

For example, when comparing object to string, the object a gets converted into a string before comparison. a.toString() gives us "[object Object]" which is equal to the string.

even weirder...

And then there's this.

What do you think this does?

var c;

if(!c){
    console.log('c is undefined')
}
else{
    console.log('c is damn fine');
}

But how about this?

if(c == false){
    console.log('c is undefined')
}
else{
    console.log('c is damn fine');
}

Guess what, !c is not the same as c == false (!!)

JavaScript converts our variable into a boolean (which is falsey), then applies the ! to reverse the value (to be truthy).

Whereas c == false, does it's own special thing where it compares undefined and false and decides it's not the same thing (which is falsey).

don't ever compare undefined or null to true and false

not that you should be doing that in the first place.

   undefined == null // rules of JavaScript say these are equal
   null == undefined
=> true

   undefined == true // expected, undefined isn't a true value
=> false

   undefined == false // wait, but why?
=> false

null and undefined are their own special values.

Nothing equals to null or undefined except for null and undefined. But both have 'falsey' values, i.e. if(undefined/null){} will not execute.

takeaways

  • !c is not the same as c == false.
  • null and undefined have their own rules about truth and falsity
  • when comparing values of different types, values get converted to the same type, according to some rules (see further reading)
  • just use strict equality already, geez

further reading

  • Equality comparisons and sameness link - check out the table for comparisons to find out what conversions happen when comparing different types.
  • Truthy and falsey - link

scope

where does a variable live?

there are two types of scopes in JavaScript.

global

var hello = 2;

function hi(){
    console.log(hello); //=> 2
}

local

function hi(){
    var hi = 8;
}

console.log(hi); //=> undefined

JavaScript is function scoped

what happens here?

function foo(){
    if(true){
        var x = 100;
    }
    console.log(x) //???
}

foo();

how about this?

function foo(){
    function inner(){
        var x = 100;
    }
    console.log(x) //???
}

foo();

object scope

objects have this special thing called this which refers to that instance of an object.

here is an example where you might use it.

var me = {
    name: 'Sher Minn',
    sayName: function(){
        console.log(this.name);
    }
}
console.log(me.name); //=> Sher Minn
me.sayName(); //=> Sher Minn

sometimes, you might want to use this in a callback.

var me = {
    name: 'Sher Minn',
    sayName: function(){
        window.setTimeout(function(){
            console.log(this.name);
        }, 1000);
    }
}

console.log(me.name); //=> Sher Minn
me.sayName(); //=> undefined, 'this' is the window object

My this.name is undefined!

In JavaScript, the this object will refer to the object that is calling the callback. Not the object where the callback is created, as you would expect.

In this case, the callback is created in the me object, but called by window in setTimeout.


binding 'this'

You can get JavaScript to use a specific this.

var me = {
    name: 'Sher Minn',
    sayName: function(){
        window.setTimeout(function(){
            console.log(this.name);
        }.bind(this), 1000);
    }
}

console.log(me.name);
me.sayName(); //=> Sher Minn

more callback scoping weirdness

this code

for(var i = 0; i < 4; i++){
    setTimeout(function(){
        console.log(i);
    }, 100);
}

is expected to log 0 1 2 3. but instead logs 4 4 4 4.

why leh?

solutions commonly seen on StackOverflow:

just try Googling 'callbacks in loops javascript'. so many articles and questions.

version 1 (ugly)

create new function for every call

for(var i = 0; i < 4; i++){
    (function(ii){setTimeout(function(){
        console.log(ii);
    }, 100)})(i);;
}

version 2 (efficient)

function only created once and reused

function doThing(ii){
    setTimeout(function(){
        doThing(i);
    }, 100);
}

for(var i = 0; i < 4; i++){
    doThing(i);
}

another alternative

create new function via bind. less efficient, but also less code.

for(var i = 0; i < 4; i++){
    setTimeout(function(ii){
        console.log(ii);
    }.bind(null, i), 100);
}

takeaway

  • hey, y'alls, JavaScript is function scoped, not block scoped
  • watch out for 'this' and variable references in a callback

10 MIN BREAK

freestyle chat. ask me about:

  • Recurse Center
  • generative art
  • impostor syndrome

hoisting

Suppose we try to use a non-existent variable

console.log(foobar); //=> ReferenceError: foobar is not defined

Suppose we try to use a variable BEFORE it was declared

console.log(foobar); //=> undefined. but the variable exists?
var foobar = 'hi peoples';

why ???????

What really happens when var foobar = 'hi peoples' is run?

  1. the foobar variable is declared
  2. foobar is initialized the value 'hi peoples'
var foobar = 'hi peoples';

is equivalent to

var foobar;
foobar = 'hi peoples';

Turns out JavaScript breaks it down to those two steps down. Then it does this thing called hoisting.

In action:

console.log(foobar);
var foobar = 'hi peoples';

is interpreted as:

var foobar; // variable DECLARATION hoisted
console.log(foobar);
foobar = 'hi peoples'; // variable initialization happens here

hoisting happens for variable and function declarations.

Back to the example I gave. This works:

foo(); //=> 'hi foo'

function foo(){
    console.log('hi foo');
}

because JavaScript hoists the whole function to the top before it runs

// foo is hoisted up!
function foo(){
    console.log('hi foo');
}
foo(); //=> 'hi foo'

And this doesn't...

foo(); // throws TypeError: foo is not a function

var foo = function(){
    console.log('hi foo');
}

Because only the variable declaration is hoisted.

var foo;
foo(); // throws TypeError: foo is not a function (because foo is still undefined)

foo = function(){
    console.log('hi foo');
}

takeaways

  • var and function declarations get hoisted to the top before code is run
  • but values still get assigned at their original locations

JavaScript, the nice parts

JavaScript allows for flexible use of functions

this one weird trick

How do you find the largest number in an array?

var arr = [4, 6, 9, 0, 1, 2];

Have you heard about Math.max()?

Math.max(4, 6) //=> 6

It takes as many arguments as you want.

Math.max(4, 6, 9) //=> 9

But.. our numbers are in an array? Well...

Math.max(arr) //=> doesn't work. tries to sort the array as an element

In JavaScript though, you can do this (kinda like unpacking, if you're familiar with that):

Math.max.apply(null, arr) //=> ???

JavaScript is eloquent

forEach

how would you iterate through an array?

for(var i = 0; i < arr.length; i++){
    console.log(arr[i]);
}

you can do this the functional way. look at how nice and clean it is!

arr.forEach(function(elem){
    console.log(elem);
}

map, reduce, filter

also check these out as clean ways to manipulate arrays

given an array, how would you square each element?

map to perform an operation on each element

[1,2,3].map(function(elem){ return elem*elem }) // => [1, 4, 9]

how would you total numbers?

reduce to 'reduce' an array in some way (e.g. total)

[1,2,3].reduce(function(total, elem){ return elem+total }, 0) // => 6

how would you only pick out even numbers?

filter to filter out based on a condition

[1,2,3,4].filter(function(elem){return elem % 2 == 0; }) // => [2, 4]

takeaway

  • JavaScript can be hella sexy if you want it to be.

closing words

ahhh JavaScript is so weird! why do you even like it?

  1. JavaScript is just a misunderstood teenager everyone likes to poke fun at
  2. but actually, isn't that bad when you try to understand it
    • beacase it's so weird, you get to dive really deep
  3. and turns out it's secretly cool
    • it's hella dynamic
    • does cool visual things in-browser
    • JavaScript engines (such as V8 that runs in Chrome) are pretty efficient
  4. so, make JavaScript your friend

how to make JavaScript your friend

  • write vanilla JavaScript
    • frameworks are great, but they don't allow you to understand the basics
    • i didn't have the chance to properly understand JavaScript during my JQuery/AngularJS days
    • e.g. try implementing a tabs library in vanilla JavaScript
    • you'd be surprised at how much you can do without JQuery.
  • understanding things like these will make you a better programmer (i promise):
    • scope
    • closures
    • hoisting
    • prototype, classes, inheritance
    • event callback loop
    • call, bind, apply
  • there are many ways to do one thing. pick one that makes sense to you and stick with it.
  • use 'use strict' mode. it will get your browser to check for potentially dangerous JavaScript code
  • use ES6 JavaScript, a newer spec of JavaScript that is a lot more standardized.
@alamnr
Copy link

alamnr commented Jul 13, 2018

nice job, thank you sir, get a bird's eye view of your github profile summary here - https://alamnr.github.io/profile.html?user=piratefsh, it will be great if you review my js code of this project's repo (https://github.com/alamnr/alamnr.github.io/blob/master/js/new_git_promise.js) and suggest me for improvement - thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment