JavaScript

The Good - The Bad - The Ugly

JavaScript

The Ugly - The Bad - The Good

The Ugly

true
> [] + []
''
> [] + {}
'[object Object]'
> {} + []
0
> alert.call.call.call.call.call.apply(function (a) {return a}, [1,2])
2
> true === 1
false
> true + true === 2
> 9999999999999999
10000000000000000
> 0.1 + 0.2 === 0.3
false
> '2' + 1
'21'
> '2' - 1
1
> 0 === -0
true
1/0 === 1/-0
false
> x === x + 1
true
true
1 / 0 === Infinity
false
> NaN == NaN
false
> isNaN(NaN)
> isNaN("foo")
true
> Number.isNaN(NaN)
true
> Number.isNaN("foo")
false
> NaN !== NaN
true
> parseInt(NaN, 24)
13511
> parseInt("20foo") / Number.parseInt("20foo")
20
> NaN === NaN
true
1 / -0 === -Infinity
true
> +"20foo"
NaN
> Number.parseInt('20foo') == '20foo'
false
false
> typeof Infinity
false
> Number.MIN_VALUE
5e-324
> Math.max() > Math.min()
> Math.max()
-Infinity
> Math.min()
Infinity
> Number.MIN_VALUE < 0
Number
> typeof NaN
Number
> [10, 9, 8, 3, 2, 1, 0].sort()
[0, 1, 10, 2, 3, 8, 9]
> (![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
'fail'
> [,,,].length
3
> Math.min(0, -0)
-0
> Math.max(0, -0)
0
false
> 1 < 2 < 3
true
> typeof 'foo'
'string'
> 'foo' instanceof String
> new String('foo') == 'foo'
true
> typeof new String('foo')
> 3 > 2 >= 1
true
> 3 > 2 > 1
false
'object'
> f = () => 10; f()
10
> f = () => {}; f()
undefined
> Number()
0
> Number(undefined)
NaN
> <!-- valid comment too
> ''+[]
'0'
> Object.defineProperty(Object.getPrototypeOf([]), "toString", {
  value: function toString() {
    return this.length;
  },
  configurable: false,
  writable: false
});
> Number.parseInt(12)
NaN
> Object.defineProperty(Number, "parseInt", {
  value: function parseInt() {
    return NaN;
  },
  configurable: false,
  writable: false
});
> Number.parseInt
ƒ parseInt() { [native code] }
> Number.parseInt.toString = function() { return "parseInt() { [native code] }" };
> Object.defineProperty(Number, "parseInt", {
  value: function parseInt() {
    return NaN;
  },
  configurable: false,
  writable: false
});

Fragen?

The Bad

Beware the context

var x = {
 foo() {
   return this;
 },
};
var y = x.foo;

x.foo();
y();
function foo() {
  return this;
}

foo.call(console);
foo.call(undefined);
foo.bind(foo)();
var foo = {
  number: 1,
  foo() {
    return this.number;
  }
};
var bar = {
  number: 23;
};
var x = foo.foo;
foo.foo();
x();
x.call(bar);

Optimisation

Declarations

  • __proto__
  • get
  • set

     
  • debugger
  • eval()
  • with

The Good

Let & Const

var foo = 1;
{
    var foo = 2;
}
console.log(foo);
// 2
var foo = 1;
{
    let foo = 2;
}
console.log(foo);
// 1
var foo = 1; // this is const, do not change!

function evil() {
    foo = 2;
}
evil();
console.log(foo);
// 2
const foo = 1; // this is const, do not change!

function evil() {
    foo = 2;
}
evil(); // TypeError, Assignment to constant variable.
console.log(foo);
const foo = { a: 1 };
foo.a = 2;
console.log(foo.a);
// 2
var foo = 1;
var foo = 2;
let foo = 1;
const foo = 2; // Throws, foo already declared

Destructuring

var foo = {
  bar: 1,
  batz: 2
};
var bar = foo.bar;
const foo = {
  bar: 1,
  batz: 2,
};
const { bar } = foo;
var a = [1, 2, 3]
var b = a[0];
var c = a[2];
const a = [1, 2, 3];
const [b, , c] = a;
function foo(a) {
    if (a === undefined) {
        a = 1;
    }
}
var a = 1;
var b = 2;
// Swap
var c = a;
a = b;
b = c;
const a = 1;
const b = 2;
// Swap
[a, b] = [b, a]
function foo(a = 1) {
}
function foo(a = { a: 1, b: 2 }) {}
function bar({ a = 1, b = 2 }) {}
function bar({ a = 1, b = 2 } = {}) {}

Spread & Rest

function foo() {
    var a = arguments; // EVIL!
}
function foo(...a) {
}
function foo(a, b, ...c) {
}
var a = [1, 2, 3];
var b = [2, 4, 6];
var c = a.concat(b);
const a = [1, 2, 3];
const b = [2, 4, 6];
const c = [...a, ...b];
console.log.apply(console.log, ...[1, 2, 3]);
console.log.call(console.log, 1, 2, 3);
function foo(...a, b, ...c) { // NOPE
}

Arrow Functions

function() {
    return 1;
}
() => 1
function() {
    return { a: 1 };
}
function(a) {
    return a;
}
var self = this;
function() {
    return self.foo;
}
() => this.foo;
a => a
() => ({ a: 1 });

Template Literals

var x = 'foo\nbar';
const x = `foo
bar`;
var a = 'foo' + 1 + 'bar';
const a = `foo ${1} bar`;

Object Literals

var x = {
    foo: function() {},
    bar: bar,
};
x['batz'] = 123;
const x = {
    foo() {},
    bar,
    ['batz']: 123,
};

Classes

 

class Foo extends Bar {
    static foo = 123;        // ESNext (Stage 2)
    foo = 123;               // ESNext (Stage 3)
    constructor() {
        super();
    }
    static bar() {
    }
    bar() {
        super.bar();
    }
}

new Foo().bar();
Foo.foo;

Promises

function later () {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("yay"), 1500)
  })
}

function muchLater () {
  return later().then(later)
}

const p = later()

p
  .then(x => x.y.z)
  .catch(err => console.error(err))
  .then(muchLater)
  .then(x => console.log(x))
  .then(x => console.log(x))

const p2 = p.then(later)
p2.then(x => console.log(x))
p2.then(x => x.y.z)
  .catch(err => console.error(err))
  .then(x => fetch("http://google.com"))

Promises

Generators

function* generator() {
  yield 'f'
  yield 'o'
  yield 'o'
}
const foo = generator();
for (let bar of foo) {
    console.log(bar)
}
// 'f'
// 'o'
// 'o'
[...foo()]
// ['f', 'o', 'o']
function* genGenerator() {
    yield* 'foo';
}

[...genGenerator()];
// ['f', 'o', 'o']
function* generator() {
    yield 1;
    console.log(1);
    yield 2;
    console.log(2);
    yield 3;
    console.log(3);
}
function* generator() {
    yield 1;
    yield 2;
    return 3;
    yield 4;
}
// [...generator()]
// [1, 2]

Async / Await

function a() {
    return Promise.resolve()
    .then(() => 1);
}
async function a() {
    await Promise.resolve();
    return 1;
}
function b() {
    return a()
    .then(n => n + 1);
}
async function b() {
    const n = await a();
    return n + 1;
}
let a = (() => {
    var ref = _asyncToGenerator(function* () {
        yield Promise.resolve();
        return 1;
    });

    return function a() {
        return ref.apply(this, arguments);
    };
})();

let b = (() => {
    var ref = _asyncToGenerator(function* () {
        const n = yield a();
        return n + 1;
    });

    return function b() {
        return ref.apply(this, arguments);
    };
})();

Maps, Sets, Weak

  • Iterable
  • Key, Value Pairs
  • Key beliebig
  • Kein Iterable
  • Key, Value Pairs
  • Key muss Reference sein
  • Zählt nich als ref für GC!

Map

WeakMap

  • Iterable
  • Value List
  • Value beliebig
  • Kein Iterable
  • Key, Value Pairs
  • Value muss reference sein
  • Zählt nich als ref für GC!

Set

WeakSet

Symbols

const symbol = Symbol();
const descriptiveSymbol = Symbol('foo');
symbol !== Symbol();
descriptiveSymbol !== Symbol('foo');
const S1 = Symbol.for('foo');
const S2 = Symbol.for('foo');

S1 === S2
const foo = {
  [Symbol()]: 'foo',
  [Symbol('foo')]: 'bar',
  [Symbol.for('bar')]: 'baz',
  what: 'ever'
};
console.log(Object.keys(foo))
// <- ['what']

console.log(JSON.stringify(foo))
// <- {"what":"ever"}

for (let key in foo) {
  console.log(key)
  // <- 'what'
}

console.log(Object.getOwnPropertyNames(foo))
// <- ['what']

console.log(Object.getOwnPropertySymbols(foo))
// <- [Symbol(), Symbol('foo'), Symbol.for('bar')]

Linting

Linting History

  • JSLint
  • JSHint
  • JSCS
  • ESLint

Transpiler

Auswahl

Babel Facebook
Closure Google
Traceur Google
Typescript Microsoft

Focus Babel

Transpiler - Babel

  • ES6 (Next) rein, ES5 raus
  • Plugin basiert
  • Ohne Plugin 0 Funktion
  • Polyfill (babel-polyfill)
  • JSX (React)
  • Flow support

Beispiel

class Foo extends Bar {
    static foo = 123;        // ESNext
    foo = 123;               // ESNext
    constructor() {
        super();
    }
    static bar() {
    }
    bar() {
        super.bar();
    }
}

new Foo().bar();
Foo.foo;

Beispiel

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Foo = function (_Bar) {
    _inherits(Foo, _Bar);
    // ESNext
    function Foo() {
        _classCallCheck(this, Foo);

        var _this = _possibleConstructorReturn(this, _Bar.call(this));

        _this.foo = 123;
        return _this;
    } // ESNext

    Foo.bar = function bar() {};

    Foo.prototype.bar = function bar() {
        _Bar.prototype.bar.call(this);
    };

    return Foo;
}(Bar);

Foo.foo = 123;


new Foo().bar();
Foo.foo;

Modules

Modul Standards

  • Globals
  • AMD (Asynchronous module definition)
  • UMD (Universal module definition)
  • CommonJS (Node)
  • ES2015
  • Globals
  • AMD (Asynchronous module definition)
  • UMD (Universal module definition)
var a = require('./a');
a.foo();

var b = require('./b');
b();
import { a } from './a';
import andererName from './b';

a();
andererName();
module.exports = {
    a: function() {
        return 'Ich bin a';
    }
};
module.exports = function() {
    return 'Ich bin b';
}

a.js

b.js

export function a() {
    return 'Ich bin a';
}
export default function() {
    return 'Ich bin b';
}

Funktioniert so (fast) nirgends

 

Standard existiert, Node bleibt bei CommonJS (vorerst)

Inzwischen gibt es flags für node (mjs)

Tooling to the rescue!

Browser -> Bundler

Node -> Babel

Bundler

  • Browserify
  • Webpack
  • Rollup

Wer nutzt JS überhaupt?

ALLE

Größere Projekte?

  • Netflix TV Interface (React fork)
  • Netflix Backend
  • Facebook (Unzählig viel)
  • Cloudflare
Made with Slides.com