Modern JavaScript
Baumgartner - @ddprrt - Nov 2020
Modern JavaScript Baumgartner - @ddprrt - Nov 2020 Brendan Eich JS - - PowerPoint PPT Presentation
Modern JavaScript Baumgartner - @ddprrt - Nov 2020 Brendan Eich JS had to look like Java only less so, be Javas dumb kid brother or boy- hostage sidekick. Plus, I had to be done in ten days or something worse than JS would have
Baumgartner - @ddprrt - Nov 2020
Syntax
Strings, Arrays, Regular Expressions
functions
Prototype inheritance
Closures
Event Handlers
var person = { name: "Stefan", age: 38 }
function greet(name) { alert("Hello " + name) } function stefanize(funcs) { funcs("Stefan") } stefanize(greet)
function greet(name) { return function(greeting) { alert(greeting + ", " + name) } } greet("Stefan")("Salut")
var lifeform = { greet: function() { alert("Hello, " + this.name) }, species: function() { alert("I am a " + this.species) } } function Person(name) { this.name = name this.species = "Human" } function Dog(name, kind) { this.name = name this.species = "Dog" this.kind = kind } Person.prototype = lifeform Dog.prototype = lifeform var stefan = new Person("Stefan") stefan.greet() var waldi = new Dog( “Waldi”, “Dackel” ) waldi.greet()
/0 types as objects var message = new String("Hello")
/0 types as objects var message = new String("Hello") /0 And the Y2K bug in Date
/0 types as objects var message = new String("Hello") /0 And the Y2K bug in Date
Stefan Baumgartner
Bryan Cantrill
JavaScript’s inception
1995
1996
Introduction of JScript
1995
1996 1995
ECMAScript Standardization
1997
1996 1995 1997 1999
ECMAScript 3 RegEx, better String handling try/catch, etc.
1996 1995 1997 1999
ECMAScript 4 abandoned Classes, interfaces, types, …
2003
1996 1995 1997 1999 2003 2009
ECMAScript 5 “strict” mode, property descriptors JSON, ….
1996 1995 1997 1999 2003 2009
1996 1995 1997 1999 2003 2009
ECMAScript 6 / ES2015 Classes, modules, better for loops Destructuring, Promises, Arrow functions Generators …
2015
1996 1995 1997 1999 2003 2009 2015
2017 1996 1995 1997 1999 2003 2009 2015 2016 2018
https://www.ecma-international.org/activities/Languages/Language%20overview.pdf
/0 ES5 var x = 0 if(someCondition) { var x = 1 } console.log(x) /0 x => 1
/0 ES6+ let x = 0 if(someCondition) { let x = 1 } console.log(x) /0 x => 0
const x = "Stefan" x = 2 /0 Uncaught TypeError: /0 Assignment to constant variable.
const person = { name: "Stefan" } person.age = 38 person.name = "Not Stefan"
const assignments are block scoped const assignments are immutable reference assignments Objects, Arrays, Sets can still be mutated
const position = [10, 20] const x = position[0] const y = position[1] /0 Destructuring! const [x, y] = position const [a, b, ../rest] = [1, 2, 3, 4, 5]; /0 rest operator ../ console.log(a); /0 1 console.log(b); /0 2 console.log(rest); /0 [3, 4, 5]
function getPosition() { return { x: 50, y: 200, z: 13 }; } const { x, y } = getPosition(); /0 renames const { z : zIndex } = getPosition(); /0 defaults const { a = 0 } = getPosition();
/0 ES5 var name = "Stefan"; var age = 38; var person = { name: name, age: age, whoami: function() { return "I am " + this.name + " and I am " + this.age + "years old" } }
/0 ES6+ const name = "Stefan"; const age = 38; const person = { name, age, whoami() { /0 String template literals return `I am ${this.name} and I am ${this.age} years old` } }
Template literals can have any expression within ${} and are multiline
for (let value of myArray) { /0 ../ } for (let index of myArray.keys()) { /0 ../ } for (let [index, value] of myArray.entries()) { /0 ../ } for (let key in myObject) { }
/0 Default parameters function setVAT(price, vat = 0.2) { return price * (1 + vat) } /0 Destructuring function printPerson({ name, age }) { /0../ } /0 Rest arguments function recursivePrint(el, ../rest) { console.log(el); recursivePrint(rest) } recursivePrint(1, 2, 3, 4, 5, 6)
const shout = (name) =? name.toUpperCase()
Arrow functions are strictly anonymous Adding a block { } after the arrow requires a return statement Wrap objects in parens to return them immediately Arrow functions are lexical scoped: this is either module scope, class scope, or last function scope
/0 passing arguments as list fn(1, 2, 3) /0 as array fn(../[1, 2, 3]) /0 concatenation /0 z => [1, 2, 3, 4, 5, 6, 7] const z = [1, 2, ../[3, 4, 5], 6, 7] /0 cast lists to arrays const imgs = [../document.querySelectorAll("img")] /0 merge Objects const person = { ../nameAndAge, ../personFunctions }
/0 ES5 function Car () { this.fuel = 0; this.distance = 0; } Car.prototype.move = function () { this.fuel-.; this.distance += 2; } Car.prototype.addFuel = function () { this.fuel+, }
/0 ES6+ class Car { constructor () { this.fuel = 0 this.distance = 0 } move () { this.fuel-.; this.distance += 2; } addFuel () { this.fuel+,; } }
Classes are
Classes are not
conventient
Baumgartner - @ddprrt - Nov 2020
49827
£ …
Vlad Riscutia
Vlad Riscutia
http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%201st%20edition,%20June%201997.pdf
https://exploringjs.com/impatient-js/ch_values.html
TS
JS
2017 1996 1995 1997 1999 2003 2009
ECMAScript 6 / ES2015
2015 2016 2018
2017 1996 1995 1997 1999 2003 2009
ECMAScript 6 / ES2015
2015 2016 2018 2011
TypeScript’s inception
https://channel9.msdn.com/Shows/Going+Deep/Anders-Hejlsberg-and-Lars-Bak-TypeScript-JavaScript-and-Dart
Non-goal: Apply a sound or "provably correct" type system. Instead, strike a balance between correctness and productivity.
function addVAT(price, vat) { return price * (1 + vat) // Oh! You add and multiply with numbers, so it's a number } addVAT2(2, 0.2).toUpperCase() // Immediate Krawutzikaputzi function addVAT(price, vat = 0.2) { // great, `vat`is also number! return price * (1 + vat) } /** * Adds VAT to a price * * @param {number} price The price without VAT * @param {number} vat The VAT [0-1] * * @returns {number} */ function addVAT(price, vat = 0.2) { return price * (1 + vat) }
/** * @typedef {Object} Article * @property {number} price * @property {number} vat * @property {string} string * @property {boolean=} sold */ /** * Now we can use Article as a proper type * @param {[Article]} articles */ function totalAmount(articles) { return articles.reduce((total, article) => { return total + addVAT(article) }, 0) }
function addVAT(price: number, vat: number): number { return price * (1 + vat) } // or: declare, don’t implement (aka Header file, file comes from a different lib) declare function addVAT(price: number, vat: number): number;
const defaultOrder = { articles: [ { price: 1200.50, vat: 20, title: 'Macboox Air Refurbished - 2013' }, { price: 9, vat: 0, title: 'I feel smashing subscription' } ], customer: { name: 'Fritz Furball', address: 'Smashing Hill, 90210', dateOfBirth: new Date(2006, 9, 1) } } This object would make a good type type Order = typeof defaultOrder; function checkOrders(orders: Order[]) { return orders.reduce((valid, order) => { return valid && order.articles.length > 0 }, true) } typeof creates types on the fly
const gift = { price: 0, vat: 0, title: 'A bottle opener', } as const; // gift.price = 100; // this breaks const context makes true const objects
interface Named { name: string; } class Person { name: string; } let p: Named; // OK, because of structural typing p = new Person(); interface Named { name: string; } let x: Named; // y's inferred type is { name: string; location: string; } let y = { name: "Alice", location: "Seattle" }; x = y;
number string boolean Symbol Object null undefined
number string boolean Symbol Object null undefined
any unknown
number string boolean Symbol Object null undefined
never
number string boolean Symbol Object null undefined
number string boolean null undefined
number string boolean null undefined true false
1000000 NaN 6 120.3 … … ‘Hello world’ ‘Baumi’
true false
1000000 NaN 6 120.3 … … ‘Hello world’ ‘Baumi’ null undefined
number string boolean true false
1000000 NaN 6 120.3 … … ‘Hello world’ ‘Baumi’ null undefined
number string boolean true false
1000000 NaN 6 120.3 … … ‘Hello world’ ‘Baumi’ null undefined
{ a: string } { b: string } { a: string, b: string }
type Talk = { speaker: string, title: string, abstract: string } type TechEvent = { title: string, description: string date: Date, capacity: number, rsvp: number } We want to create Tech events that are tech events, but a little bit more type Meetup = TechEvent & { type: 'meetup' location: string, price: 'free', talks: Talk[] } type Conference = TechEvent & { type: 'conference', location: string, price: number, talks: Talk[] } type Webinar = TechEvent & { type: 'webinar', url: string, videoUrl: string, talks: Talk } Intersection types! type TechEvents = Webinar | Conference | Meetup; Union types!
declare class Widget { toJSON(): { kind: "Widget", date: Date } } type Item = { text: string; count: number; choice: "yes" | "no" | null; func: () => void; nested: { isSaved: boolean; data: [1, undefined, 2]; } widget: Widget; children: Item[]; } declare let item: JSONified<Item>; type JSONified<T> = JSONifiedValue<T extends { toJSON(): infer U } ? U : T>; type JSONifiedValue<T> = T extends string | number | boolean | null ? T : T extends Function ? undefined : T extends Array<infer U> ? JSONifiedArray<U> : T extends object ? JSONifiedObject<T> : undefined; type UndefinedAsNull<T> = T extends undefined ? null : T; interface JSONifiedArray<T> extends Array<UndefinedAsNull<JSONified<T>>> {} type JSONifiedObject<T> = { [P in keyof T]: JSONified<T[P]> }
type AllElements = { 'a': HTMLAnchorElement; 'div': HTMLDivElement; 'span': HTMLSpanElement; 'ul': HTMLUListElement; 'title': HTMLTitleElement; 'textarea': HTMLTextAreaElement; 'template': HTMLTemplateElement; 'tfoot': HTMLTableSectionElement; 'thead': HTMLTableSectionElement; 'tbody': HTMLTableSectionElement; 'tr': HTMLTableRowElement; 'table': HTMLTableElement; 'col': HTMLTableColElement; 'colgroup': HTMLTableColElement; 'th': HTMLTableHeaderCellElement; 'td': HTMLTableDataCellElement; 'caption': HTMLTableCaptionElement; 'style': HTMLStyleElement; 'select': HTMLSelectElement; 'script': HTMLScriptElement; 'blockquote': HTMLQuoteElement; 'q': HTMLQuoteElement; } Map types type JSXHTMLElement<T extends keyof AllElements> = AllElements[T]; type JSXElement<T extends string> = T extends keyof AllElements ? JSXHTMLElement<T> : HTMLElement; Mapped types Conditional types
function shouting(param: any) { if(typeof param === 'string') { // i am a string return param.toUpperCase() } else if(typeof param === 'number') { // i am a number return `${param}`.toUpperCase() } return 'I HAVE NO IDEA WHAT TO DO' }
class Vendor { name: string; constructor(name: string) { this.name = name; } greet() { return "Hello, welcome to " + this.name; } } Which parts are JS, which are TS? class FoodTruck extends Vendor { cuisine: string; constructor(name: string, cuisine: string) { super(name); this.cuisine = cuisine; } greet() { return "Hi, welcome to food truck " + this.name + ". We serve " + this.cuisine + " food."; } }