class: title, center, middle name: title # Javascript: Down the Rabbit Hole Presented by Allen Zheng to the [Linux Users Group at Georgia Tech](https://lugatgt.org) 2017-03-08 --- # Meta - Your presenter: Allen Zheng ([@strburst](https://github.com/strburst/)) ??? - I'm your presenter; it's my first time presenting to the LUG -- - Presentation license: CC-BY-SA - Code license: MIT -- - Presentation framework: [remark.js](https://remarkjs.com/) -- - Presentation url: https://strburst.github.io/nodejs-lug-slides/ --- name: why-title # Why? -- name: why-everywhere - Javascript is everywhere ??? - Why you should care about Javascript? --- template: why-everywhere - In the browser .center[![Browser logos](https://i.imgur.com/Aym0atz.png)] --- template: why-everywhere - On the server [.center.bg-black[
]](https://nodejs.org) ??? - But what if I don't care about frontend webdev? - Originally going to talk about *just* node.js, then js + node.js, then just js - Maybe a future talk --- name: why-everywhere-desktop template: why-everywhere - In desktop apps (!) .center[[
](http://electron.atom.io/)] ??? - But what if I don't care about webdev in general? --- template: why-everywhere - In desktop apps (!) .center[[![Atom screenshot](https://i.imgur.com/CRbsubr.png)](http://atom.io/)] --- template: why-everywhere - Extremely popular programming language by most [metrics](http://githut.info/) ??? - If you still don't care, at least it will help you read blog posts --- # [History](https://en.wikipedia.org/wiki/JavaScript#History) - Created for Netscape Navigator in 1995 ??? - Realized just server-side scripting is not enough - We need a "glue" language -- - First prototype created in 10 days by Brendan Eich ??? - Brendan Eich originally hired to implement scheme - Then it was decided it needed to be familiar to Java programmers and complement Java - Named JavaScript because of Java hype at the time -- - Javascript standardization suffered a lot during the browser wars - E.g. failed ES4 standard ??? - Microsoft had its own implementation, JScript, that was incompatible with Mozilla's - After some time, it became clear that Microsoft didn't care about making a standards-compliant implementation - ECMAScript is just a name for standardized Javascript - ECMA is European Computer Manufacturers Association -- - All browsers finally on board in 2009 when ES5 was published - Standardization has been getting better since then -- - Javascript has been changing a lot since ES6/ES2015 --- # Brendan Eich: Sorry > I talk a lot about being in a hurry, which was very true; I didn't sleep much. I did the prototype for Javascript in ten days. But really, I'd already read SICP and I'd studied Scheme, and I have no good excuse for some of these things. -- Brendan Eich, [2010](https://youtu.be/1EyRscXrehw?t=5m8s) --- # Crash courses - https://learnxinyminutes.com/docs/javascript/ - http://gnab.github.io/js-workshop/ - Javascript: The Good Parts ??? - I don't think I'll be as thorough as some of these crash courses - I will try to sample some interesting language topics instead - Exercise in programming language linguistics - Feel free to interject at any time for clarifications - I'll even take requests for particular language features I should cover - Who here is comfortable with Javascript? --- # [Objects](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects) ``` var presentation = { date: Date.now(), topic: 'Javascript', 'delete me': 'hello', // keys are arbitrary strings hello: function() { // methods are just properties assigned to functions return 'Hello world, it\'s ' + this.presenter; }, presenter: 'Allen', // trailing commas are allowed }; ``` ??? - Really easy to make objects (one of the good parts) - Objects are basically just key-value pairs - You might not believe me, but JSON is valid Javascript (there are some edge cases with numbers) - Most things in Javascript are objects (objects, arrays, functions), but not numbers -- ``` presentation.presenter; // 'Allen' presentation.nonexistent; // undefined // . and [] notation are equivalent for literals without special characters presentation.organization = 'LUG@GT'; presentation['organization'] = 'LUG@GT'; // key can be an arbitrary expression presentation['top' + 'ic']; // 'Javascript' ``` ??? - Dot vs. array notation -- ``` delete presentation['delete me']; presentation['delete me']; // undefined ``` --- name: proto-title # [Prototypal inheritance](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance) -- - Objects get layered on top of one another in a "prototype chain" - If we can't find a key in an object, we look in its prototype ``` // Hackish way var proto = { a: 'hello', b: 'world' }; var o = { a: 'hi' }; Object.setPrototypeOf(o, proto); o.a; // 'hi' o.b; // 'world' ``` ??? - Objects without classes - Original Prototypal language was Self - Lua is the other modeern programming language to have this via metatables - If you want to create an object from a template, you can use another object - Setting the prototype after the fact is very slow - This is hackish because we're setting the prototype after object creation -- name: proto-eg-shorter ``` o.hasOwnProperty('a'); // true o.hasOwnProperty('b'); // false ``` -- ``` proto.b = 'everyone' o.b; // 'everyone' ``` --- template: proto-eg-shorter ``` // To make this more of a hack, we could set __proto__ directly // __proto__ is not a standard! o.__proto__ = proto ``` --- template: proto-title - Objects inherit from Object.prototype ``` ({}).toString(); // "[object Object]" Object.prototype.hello = function() { return 'Hello, world!'; }; ({}).hello(); // 'Hello, world!' ``` ??? - Default `toString` gives the 'type' of Object - `Object.prototype.toString.call([1, 2, 3])` - Object literals inherit from Object.prototype by default - Setting properties on Object is called monkey-patching, and is frowned upon -- ``` var noProto = Object.create(null); noProto.toString(); // TypeError: noProto.toString is not a function ``` ??? - You can create an Object with no prototype with Object.create --- template: proto-title ``` function Animal(name) { // Can set properties in constructor this.name = name; } // Or add to the special prototype object directly Animal.prototype = { corporeal: true, makeNoise: function() { return '...'; }, }; ``` ??? - By convention, constructors are capitalized, however, there's nothing special about this - When 'new' is used, 'this' will be bound to a new object -- ``` function Dog(name) { Animal.call(this, name); } Dog.prototype = new Animal(); // Set up the prototype chain Dog.prototype.makeNoise = function() { return 'Bork!'; }; ``` ??? - Call is just a method on all functions - What if we defined the method in the constructor? --- template: proto-title - Typical Dog inherits from Animal relationship ``` var doggo = new Dog('Gabe'); doggo.corporeal; // true doggo.makeNoise(); // 'Bork!' Dog.prototype.isPrototypeOf(doggo); // true doggo.__proto__ === Dog.prototype; // true Animal.prototype.isPrototypeOf(Dog.prototype); // true doggo.__proto__.__proto__ === Animal.prototype; // true ``` --- template: proto-title - Less hackish way to set proto ``` var proto = { a: 'hello', b: 'world' }; var obj = Object.create(proto, { a: { writable: true, configurable: true, value: 'hi', } }); ``` --- # Concurrency - Asynchronous, nonblocking, *single-threaded* - JS was made for the browser - JS is event-driven - Executing Javascript is somewhere in the event loop - Events like clicking the mouse/typing trigger Javascript - (Not 100% single-threaded in the browser due to [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)) -- - If Javascript stops, your app stops too! - Everything that can block is made asynchronous -- - No need to think about preemption/interleaving - If something happens, it has to wait in a queue ??? event driven --- name: callbacks-title # Callbacks -- ``` setTimeout(function() { alert('hi!'); }, 1000); ``` ??? - We're exploiting first-class functions again -- .center[
Click me
] ``` document.getElementById('myBtn').addEventListener('click', function(event) { alert('Click event at (' + event.clientX + ',' + event.clientY + ')'); }); ``` --- template: callbacks-title - But how do I do all the stuff I learned about in CS 2200 with pthreads? - Do `n` things in sequence - Do `n` things concurrently and come back when you did all of them - Do `n` things concurrently and come back with the first result, ignoring the rest --- template: callbacks-title - Doing `n` things in sequence ``` setTimeout(function() { console.log('hello'); setTimeout(function() { console.log('there'); setTimeout(function() { console.log('how'); setTimeout(function() { console.log('are'); setTimeout(function() { console.log('you'); }, 600); }, 700); }, 800); }, 900); }, 1000); ``` ??? - This is clearly really annoying --- template: callbacks-title - [Callback hell!](http://callbackhell.com/) .center[![Callback hell](https://i.imgur.com/n03KZ8d.png)] ??? - If you don't structure your code properly, this is what's going to happen - There are other approaches to structuring asynchronous code like promises, generators, and async/await --- template: callbacks-title - Doing `n` things in parallel ``` var LO = 1000; var HI = 7000; var NUM_PARALLEL = 10; var thingToDoAtTheEnd = function() { console.log('We did everything!'); } var semaphore = 0; for (let i = 0; i < NUM_PARALLEL; i += 1) { setTimeout(function() { console.log('Did thing #' + i); // Remember, preemption won't hurt us, so no mutexes semaphore += 1; if (semaphore >= NUM_PARALLEL) { thingToDoAtTheEnd(); } }, Math.random() * (HI - LO) + LO); } ``` --- template: callbacks-title - Doing `n` things in parallel and ignoring everything after the first thing ``` var LO = 1000; var HI = 7000; var NUM_PARALLEL = 10; var thingToDoAtTheEnd = function() { console.log('We did one of the things!'); } var finished = false; for (let i = 0; i < NUM_PARALLEL; i += 1) { setTimeout(function() { console.log('Did thing #' + i); // Remember, preemption still can't hurt us if (!finished) { finished = true; thingToDoAtTheEnd(); } }, Math.random() * (HI - LO) + LO); } ``` --- name: wat-title # Wat -- Brief related talk: https://www.destroyallsoftware.com/talks/wat -- (Probably) wise words: > Hating on JavaScript is lame - for a language that was invented and implemented in 2 weeks, by a single guy, with ridiculous additional "requirements" shoved down his throat at gunpoint, it gets an astonishing amount of things right. Mistakes were made, sure, but at least there is a handful of unifying ideas there, and they aren't half bad. > Hating on PHP, however, *is* fun... tdammers, [2017](https://www.reddit.com/r/ProgrammerHumor/comments/5rajuw/so_true/dd5qemq/) --- template: wat-title .center[![Javascript: The Good Parts is much thinner than Javascript: The Definitive Guide](https://i.imgur.com/wR3ZxfB.jpg)] ??? ``` // When not in strict mode undefined = 2 void 0 // hack // Failing silently when assignments fail var obj = Object.freeze({ a: 'hi', b: 'there' }); obj.a = 'hello'; obj.a; // hi // Arrays are just ordinary objects [] // has no bounds checking [] + [] // Sadly, + is not always commutative [] + {} {} + [] // typeof is not always useful typeof undefined, {}, function, [], NaN, null ``` --- name: jsf-title template: wat-title - [JSFuck](https://github.com/aemkei/jsfuck) - "Write any Javascript with 6 characters: `[]()!+` -- ``` // Equivalent to 'alert(1)' [][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[ ]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[] ])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+ (!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+ !+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![ ]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![] +[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[ +!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!! []+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![ ]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[ ]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![ ]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(! []+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[]) [+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+( !![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[ ])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])() ``` ??? What's going on? - We are getting special values like undefined - Then we are coercing them to strings and indexing into them to get characters - Then we are concatenating some code together and evaling it Please no questions! --- template: jsf-title - Try it yourself: http://www.jsfuck.com/ - Express `['a', 'b', 'c'].forEach(console.log)` in 59380 characters! --- name: fun-title # Semicolons - ["Semicolons in Javascript are optional"](http://mislav.net/2010/05/semicolons/) - "automatic semicolon insertion" ??? - Semicolons are not required despite C-like syntax -- ``` function f() { return // ; { an: 'object', } } function g() { return // ; a + b } ``` ??? - There are a few gotchas to be aware of --- template: fun-title ``` // lines that begin with '('... a = b + c (d + e).prop() // ...will be joined with the previous line a = b + c(d + e).prop(); ``` ??? - Strictly speaking, this makes Javascript whitepsace sensitive - Not widely used because Douglass Crockford said so --- # ES2015/ES6 - Formerly called ES6, then renamed to ES2015 ??? - Renamed because the Ecmascript committee is just going to release whatever new stuff they added to the spec every year -- - Changes Javascript as a language *a lot* - But without breaking backwards compatibility! ??? - Breaking backwards compatibility in Javascript is actually not an option - The result would be a disaster -- - Adds tons of syntactic sugar --- name: scope-title # Scope ([`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)) -- name: scope-function-scope - Javascript is the only language that has *function-scope* -- ``` (function() { if (true) { var x = 12; } return x; })(); // 12 x; // ReferenceError: x is not defined ``` ??? - This is an Immediately Invoked Function Expression (IIFE) - All the programming languages you know and love probably have lexical scoping -- ``` (function() { if (false) { var x = 12; } return x; })(); // undefined x; // ReferenceError: x is not defined ``` --- template: scope-function-scope - What really happened ``` (function() { var x; if (false) { x = 12; } return x })(); // undefined x // ReferenceError: x is not defined ``` ??? - `var` declaration hoiseted to the top of the function --- name: scope-let-const template: scope-function-scope - ES2015 adds lexical scoping with `let` and `const` keywords -- ``` (function() { if (true) { let x = 12; } return x; // ReferenceError: x is not defined })(); ``` --- template: scope-let-const - `const` does not allow reassignment ``` let x = 12; x += 1; const y = 12; y += 1; // TypeError: Assignment to constant variable ``` --- name: arrow-title # [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - New syntax for function literals ``` (param1, param2, ...) => { code } (param1, param2, ...) => value ``` -- - Advantage: much shorter ``` [1, 2, 3].map(function(elem) { return elem * 2; }); // [2, 4, 6] // Implicit return! [1, 2, 3].map(e => e * 2); // [2, 4, 6] ``` -- - There are also some optimizations like fixing `this` and not setting the `arguments` object, but I don't feel like explaining it --- name: promises-title # [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) -- - Convert a callback to a promise ([source](http://stackoverflow.com/questions/39538473/using-settimeout-on-promise-chain)) ``` function timeout(ms) { return new Promise(function(resolve, reject) { setTimeout(resolve, ms) }); } ``` - Do thing(s) with the result ``` timeout(1000).then(() => { console.log('hello'); }).then(() => { console.log('there'); }); ``` ??? - Don't worry too much about this, but basically you can convert any callback to a Promise - http://stackoverflow.com/questions/39538473/using-settimeout-on-promise-chain - We can string any number of `then`s together --- template: promises-title - Doing `n` things in sequence ``` timeout(1000).then(() => { console.log('hello'); return timeout(900); }).then(() => { console.log('there'); return timeout(800); }).then(() => { console.log('how'); return timeout(700); }).then(() => { console.log('are'); return timeout(600); }).then(() => { console.log('you'); }).catch(() => { console.log('I didn\'t know timeouts could fail!'); }); ``` ??? - Flattens out code and makes it look more synchronous --- template: promises-title - Doing `n` things in parallel ``` var LO = 1000; var HI = 7000; var NUM_PARALLEL = 10; var promises = []; for (let i = 0; i < NUM_PARALLEL; i += 1) { promises.push(timeout(Math.random() * (HI - LO) + LO).then(() => { console.log('Did thing #' + i); })); } Promise.all(promises).then(() => { console.log('We did all the things!'); }); ``` --- template: promises-title - Doing `n` things in parallel and ignoring everything after the first thing ``` var LO = 1000; var HI = 7000; var NUM_PARALLEL = 10; var promises = []; for (let i = 0; i < NUM_PARALLEL; i += 1) { promises.push(timeout(Math.random() * (HI - LO) + LO).then(() => { console.log('Did thing #' + i); })); } Promise.race(promises).then(() => { console.log('We did one of the things!'); }); ``` --- # Stuff I didn't talk about - Javascript tooling/npm - Compile-to-JS languages (Coffeescript, Typescript) - Chrome DevTools - Transpilation - node.js - Tons of language features/quirks - Even more [ES2015](https://babeljs.io/learn-es2015/) (and [ES2016](http://www.2ality.com/2016/01/ecmascript-2016.html)) features - Template strings, default/rest parameters, spread operator, generators, class syntax - Optimization/optimization killers --- # Questions? ??? Thanks for coming!