Defense Against The

JAVASCRIPT  Dark Arts

http://bit.ly/js-dark-arts

James Q Quick

DEVELOPER. SPEAKER. TEACHER.

@jamesqquick

www.learnbuildteach.com

STICKERS!!!

Tweet me @jamesqquick and include hashtag #LearnBuildTeach

Why This Talk??

JavaScript is SCARY!!

On to the spells...

Mastering Equality

1.

"Dobby is a free elf!"

Double Equals

//Double equals compares loose equality using coercion
1 == '1' //true
false == 0 //true
false == '0' //true
0 == "" // true
"" == false //true
null == undefined //true

"Falsy Values"

//false
//0
//"",
//null
//undefined
//NAN

"Falsy Values"

function printName(name){
    if(!name){
        console.log("YOU AINT GOT NO NAME!!");
    }
    else {
        console.log(name);
    }
}

printName() //YOU AINT GOT NO NAME!!
printName("James") //James

Triple Equals

//Triple equals compares strong equality
//by comparing both type and value without coercion

1 === 1 //true
'Dark Arts' === 'Dark Arts' //true
true === true
1 === '1' //false
false === 0 //false
false === '0' //false
0 === "" // false
"" === false //false

Pass by Value

//Primitives are passed by value
//Primitives - undefined, null, boolean, string, number
let name = "James Quick";
const name2 = name;

console.log(name == name2); //true
console.log(name === name2); //true

name = "Jessica Quick";
console.log(name == name2); //false
console.log(name === name2); //false

Pass by Value (cont.)

name =

"James Quick"

name2 =

"James Quick"

let name = "James Quick";
const name2 = name;

console.log(name == name2); //true
console.log(name === name2); //true

name = "Jessica Quick";
console.log(name == name2); //false
console.log(name === name2); //false

Pass by Value (cont.)

name =

"Jessica Quick"

name2 =

"James Quick"

let name = "James Quick";
const name2 = name;

console.log(name == name2); //true
console.log(name === name2); //true

name = "Jessica Quick";
console.log(name == name2); //false
console.log(name === name2); //false

Pass By Reference

//Objects are passed by reference
const p1 = {
    first: 'James',
    last: 'Quick',
}

let p2 = p1;
console.log(p2 === p1); //true

p1.first = "Jessica";
console.log(p2.first) //"Jessica"

p2 = { ...p1 };
console.log(p2 === p1); //false

Pass by Reference (cont.)

p1 =

p2 =

{

    first: 'James',

    last: 'Quick'

}

const p1 = {
    first: 'James',
    last: 'Quick',
}

let p2 = p1;
console.log(p2 === p1); //true

p1.first = "Jessica";
console.log(p2.first) //"Jessica"

p2 = { ...p1 };
console.log(p2 === p1); //false

Pass by Reference (cont.)

p1 =

p2 =

{

    first: 'Jessica',

    last: 'Quick'

}

const p1 = {
    first: 'James',
    last: 'Quick',
}

let p2 = p1;
console.log(p2 === p1); //true

p1.first = "Jessica";
console.log(p2.first) //"Jessica"

p2 = { ...p1 };
console.log(p2 === p1); //false

Pass by Reference (cont.)

p1 =

{

    first: 'Jessica',

    last: 'Quick'

}

const p1 = {
    first: 'James',
    last: 'Quick',
}

let p2 = p1;
console.log(p2 === p1); //true

p1.first = "Jessica";
console.log(p2.first) //"Jessica"

p2 = { ...p1 };
console.log(p2 === p1); //false

p2 =

{

    first: 'Jessica',

    last: 'Quick'

}

Use triple equals and make true copies of objects to avoid confusion.

ES6 Features

2.

YOU MUST KNOW ES6!!

Default Parameters

const add = (num1, num2) => {
    return num1 + num2;
}

console.log(add()) //NaN

Default Parameters ES5

const add = (num1, num2) => {
    if (num1 === undefined) {
        num1 = 0;
    }
    if (num2 === undefined) {
        num2 = 0;
    }
    return num1 + num2;
}
console.log(add()); //0

Default Parameters ES5

const add = (num1, num2) => {
    num1 = num1 || 0;
    num2 = num2 || 0;
    return num1 + num2;
}
console.log(add());

Default Parameters ES6

const add = (num1 = 0, num2 = 0) => {
    return num1 + num2;
}
console.log(add()); //0

Default Parameters ES5 Again

const addFromObject = (obj) => {
    return obj.num1 + obj.num2; 
    //cannot read property of undefined
}

console.log(addFromObject());

Default Parameters ES6 Again

const addFromObject = ({ num1 = 0, num2 = 0 } = {}) => {
    return num1 + num2;
}

console.log(addFromObject()); //0

Default Parameters Error Function


function requiredArg() {
    throw new Error('The argument is required');
}
function add(x = requiredArg(), y = requiredArg()) {
    return x + y;
}

add()//Error THE ARGUMENT IS EQUIRED

Template Literal Strings

let markup = "<html>\n\t<head>\n\t</head>\n\t<body>\n\t</body>\n</html>"

markup = "<html>\n\t<head>\n\t" +
    "</head>\n\t<body>\n\t</body>\n</html>"

markup = 
`<html>
    <head>
    </head>
    <body>
    </body>
<html>`;



Template Literal Strings

const printPerson = (person) => {
    console.log(person.first + " " + person.last + " lives in " + person.city + "." );
    
    console.log(`${person.first} ${person.last} lives in ${person.city}.`);
}
printPerson({first: "James", last: "Quick", city: "Memphis"});

Spread Operator - Arrays

//Make shallow copies of arrays with the spread operator

const arr1 = [1, 2, 3, 4];
const arr2 = arr1;

arr1[0] = 15;
console.log(arr2[0]); //15

console.log(arr1 == arr2); //true

const arr3 = [...arr1];
console.log(arr3 == arr1); //false

Spread Operator - Objects

//Make shallow copies of objects with the spread operator

const p1 = {
    first: 'James',
    last: 'Quick',
};

let p2 = p1;
console.log(p2 === p1); //true

p2 = { ...p1 };
console.log(p2 === p1); //false

Deep Copy? Use lodash

OR...

JSON.parse(JSON.stringify(obj))

Other ES6 Features

  • Arrow Functions
  • Promises
  • Enhanced Object Literals
  • Rest Operator
  • Const and Let variables

YOU MUST KNOW ES6!!

JavaScript 30 by Wes Bos

Asynchronous JavaScript

3.

JavaScript is SINGLE THREADED

Callbacks

//Run code after a delay
setTimeout(() => {
    console.log("1 second");
}, 1000);

//Add click event handler for a button
button.addEventListener('click', (e) => {
    console.log("Button was clicked");
});

Callback Hell

setTimeout(() => {
    console.log("5");
    setTimeout(() => {
        console.log("4");
        setTimeout(() => {
            console.log("3");
            setTimeout(() => {
                console.log("2");
                setTimeout(() => {
                    console.log("1");
                }, 1000)
            }, 1000)
        }, 1000)
    }, 1000)
}, 1000)

//5...4...3...2..1

Promises

const axios = require('axios');

const url = "http://api.icndb.com/jokes/random?firstName=James&lastName=Quick"
axios.get(url)
    .then( res => {
        console.log(res.data.value.joke);
        //"Product Owners never ask James Quick for more features. They ask for mercy."
    })
    .catch( err => {
        console.log(err);
    });

What if you need to run multiple async actions in a row?

Promise Chaining

const todoURL = "https://jsonplaceholder.typicode.com/todos/1";
const userURL = "https://jsonplaceholder.typicode.com/users/"

axios.get(todoURL)
    .then((res) => {
        console.log(res.data); //userId = 1
        return axios.get(userURL + res.data.userId);
    })
    .then(res => {
        console.log(res.data) //user object
    })
    .catch(err => {
        console.log("ERROR! " + err);
    })

Async/Await

const getJokeAsync = async () => {
    const url = "http://api.icndb.com/jokes/random?firstName=James&lastName=Quick"
    const res = await axios.get(url);
    console.log(res.data.value.joke);
}

getJokeAsync();

Async/Await

const getUserFromTodoAsync = async (todoId) => {
    const todoURL = "https://jsonplaceholder.typicode.com/todos/" + todoId;
    const userURL = "https://jsonplaceholder.typicode.com/users/"

    const res = await axios.get(todoUrl);
    const userRes = await axios.get(userURL + res.data.userId);
}

Async/Await and Try/Catch

const getTodoAsync = async () => {
    const todoURL = "https://jsonplaceholder.typicode.com/todos/1";
    const userURL = "https://jsonplaceholder.typicode.com/users/"

    try {
        const res = await axios.get(todoUrl);
        const userRes = await axios.get(userURL + res.data.userId);
    } catch (ex) {
        console.log("ERROR!" + ex);
    }
}

getTodoAsync();

Formatting and Linting

4.

What is LINTING?

Linting Benefits

  • Consistent Code Formatting
  • NO const reassignment and no undeclared variables
  • Better timing/performance with Asynchronous JS
  • No console.log()

Formatting Before and After

const name = "James";

const person = { first: name,last:"Quick"}

function printPersonName(p){
console.log(p.first, p.last);
}

...

const name = 'James';

const person = { first: name, last: 'Quick' };

function printPersonName(p) {
  console.log(p.first, p.last);
}


No Const Reassignment

No Undeclared References

Better Async Performance

No Console Log

Write BETTER code FASTER

Linting Setup

  • Install eslint package to project
  • Use `eslint --init` command 
  • follow prompts to create eslint configuration (creates .eslintrc file)
  • Install eslint extension for VS Code
  • Go into settings and check "Eslint: Auto Fix on Save"

Linting JavaScript

npm init
npm install --save eslint
eslint --init

ESLint Configuration File

{
    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true
    },
    "extends": "eslint:recommended",
    "globals": {
        "Atomics": "readonly",
        "SharedArrayBuffer": "readonly"
    },
    "parserOptions": {
        "ecmaVersion": 2018
    },
    "rules": {
        "indent": [
            "error",
            "tab"
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ]
    }
}

Preconfigured with the top front-end frameworks

TypeScript

5.

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. 

The benefits...

 Benefits of TypeScript

  • Optional static typings
  • Converts to JavaScript
  • Easily define object definitions with Interfaces
  • Documentation and Intellisense

Static Bindings - 1

function ICanAdd( num1, num2) {
    return num1 + num2;
}

ICanAdd(1,2);
ICanAdd("James", "Quick");
ICanAdd({}, []);

Static Bindings - 2

function ICanAdd(num1: number, num2: number) {
    return num1 + num2;
}

ICanAdd(1, 2);
ICanAdd("James", "Quick"); //CANT DO THAT!
ICanAdd({}, []); //CANT DO THAT!

Static Bindings - 3

function ICanAdd(num1: number, num2: number):number {
    return num1 + num2;
}

const num:number = ICanAdd(1, 2);

Static Bindings - 4


function ICanAdd(num1: number, num2: number):number {
    return num1 + num2;
}

const num = ICanAdd(1, 2); //type of number is optional since function returns a number

Static Bindings - 5


function ICanAdd(num1: number, num2: number):number {
    return num1 + num2;
}

const num = ICanAdd(1, 2);
num = "James" //YOU CAN"T DO THIS: num is of type number

Compilation -Before/After

const message: string = 'hello world';

const first = 'James';

const person = { first, last: 'Quick', age: 28 };

const { last, age } = person;

console.log(`${first} ${last} is ${age} years old!`);
var message = 'hello world';
var first = 'James';
var person = { first: first, last: 'Quick', age: 28 };
var last = person.last, age = person.age;
console.log(first + " " + last + " is " + age + " years old!");

Try out the TypeScript Playground

Interfaces/Models

interface Person  {
    first: string,
    last: string,
    age:number,
    children: [],
    spouse:Person
}

Documentation

Setup TypeScript

  • Install TypeScript via NPMx
  • Use tsc command followed by TypeScript file
  • Create TypeScript configuration file
  • Install TSLint extension VS Code

TypeScript Config

{
  "compilerOptions": {
    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [],                             /* Specify library files to be included in the compilation. */
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    // "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    // "outDir": "./",                        /* Redirect output structure to the directory. */
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
    // "removeComments": true,                /* Do not emit comments to output. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    // "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  }
}

Configurable with the top front-end frameworks

Debugging

BONUS:

console.log()

Visual Studio Code

Coupon Code - KCDC2019

Wrap Up and Resources

Useful Links

www.learnbuildteach.com

STICKERS!!!

Tweet me @jamesqquick and include hashtag #LearnBuildTeach

THANK YOU!

@jamesqquick

Defense Against the JavaScript Dark Arts

By James Quick

Defense Against the JavaScript Dark Arts

In the magical world of JavaScript, you have the power to do almost anything, but with great power comes great responsibility. Do you have the magical prowess to protect yourself from the darkest depths of JavaScript? In this talk, we discuss 5 spells that you can use protect yourself from the most common JavaScript pitfalls. Some of these are as easy as a swish and flick of the old magic wand thanks to modern JavaScript tooling, but the rest comes from establishing best practices and a new mindset. After this talk, you will walk away head high and wand at the ready!

  • 1,080