v4.0.1
async
Standardization of the general purpose, cross platform, vendor-neutral programming language ECMAScript
Five stages of which the later 4 are considered "maturity" level/stages. TC39 must approve each "change"/spec.
See the process docs tc39.github.io/process-document/
There's more Stage 3, ~16 Stage 2, ~48 Stage 1, and ~20 Stage 0 so JS will be changing indefinitely.
I don't know of any other language that has spawned so many variants.
JavaScript runs in the "event loop" which is, not surprisingly, event-driven. There is only a single thread and is essentially non-blocking; which avoids having to deal with thread management, locks or race conditions.
Essentially all IO commands are non-blocking.
There's three main components:
Additionally:
new Promise()
The Event Loop basically runs it all, basically in this priority:
But, of course, it's actually more complicated than that (tasks, microtasks, Workers, IO handlers, etc.), and there's some cross-browser variation.
The result (and purpose, really) of all this is that JavaScript is async, and that has a significant effect on how to code in JS.
"Callbacks" is the traditional way of handling async programming. This basically means passing a function (either by name or an anon function) that will be "called back" when done.
I have a medium post on async patterns with callbacks medium.com/@ToddZebert/javascript-async-patterns-a-progression-part-1-callbacks-530bc3111b55
Primitives are not objects, and are: undefined, null, boolean, string and number.
Magically, some primitives are "un/boxed" (un/wrapped) in objects when coerced: boolean, string and number.
Objects are Boolean, String, Number, Array, Object, RegExp, and Date.
Objects contain properties and methods, have a constructor from which they inherit from, are mutable, and more.
this is a property that references an object defining the context at invocation of a function.
It acts somewhat like a pronoun does in English: it points to the antecedent - i.e. the noun in a sentence.
JavaScripts this isn't too dissimilar to PHP's $this.
this doesn't have to contain the default value, it can be altered using three methods.
call and apply are very similar, and invoke a function:
aMethod.apply(myContext, myParamArray);
aMethod.call(myContext, myParam1, myParam2 /* ,etc */);
Whereas bind returns a function. It's also useful for Partial Application (a Functional Programming concept).
var newMethod = aMethod.bind(myContext, myParam1, myParam2 /* ,etc */);
newMethod(/* params */);
All can be used to "borrow" methods, or invoke/compose variable-arity (aka multi-arity) or variadic functions.
An ES5 concept that tells the JS engine to run in a slightly different way, which is beneficial but can also cause issues.
While the command can be used at the top of files, it's best in each function:
function myFunc() {
"use strict";
// do something
}
Enclosing it in quotes uses a "feature" of JS syntax that the statement is ignored by non-compliant engines.
It causes a syntax error or throws an error:
There's a handful of JS Engine specific changes also.
Since "use strict;"
was intended for ES5, changes from ES6 can cause parsing problems.
So TC-39 just decided to simply avoid these issues by disallowing stict mode within a function
definition when the function's parameters...:
"Global" strict mode (outside of function
definition) is OK, as well as wrapping within in IIFE.
ES6 Modules and Classes are intrinsically strict mode.
Every invocation of a function has both an associated scope and context.
Scope is unique to a function (and blocks in ES6+ using let
) when it is invoked, and is the access to / visibility of variables.
Context is the value of the this keyword.
Closures are a way of structuring a function such that the inner (child) function "memorizes" the outer (parent, or enclosing) local scope so that it persists between calls to the inner function.
Anytime you use the function keyword* inside a function, you are potentially creating a closure.
* Or the=>
(["fat"] Arrow functions) keyword in ES6
var myFunc = function (x) {
var myClosure = function () {
console.log(x++);
};
return myClosure;
};
var myInst = myFunc(10);
myInst(); // 10
myInst(); // 11
Do not create closures inside a loop or you're likely to get unexpected results.
Prototypal Inheritance is all about objects. Objects inherit properties from other objects.
This stresses "Composition over inheritance", i.e. avoid inheritance hierarchy. Compose objects, not object inheritance, and use Mixins and Decorators.
There's too much to get into here so I'm just going to hit some code:
function Square (side) { this.side = side; }
Square.prototype.perimeter = function () {
return this.side * 4;
};
Square.prototype.area = function () {
return Math.pow(this.side, 2);
};
var squareA = new Square(5);
var squareB = new Square(15);
squareA.area(); // 25
squareB.perimeter(); // 60
var MyParentObj = (function () {
function MyParentObj(cParam) { this.pParam = cParam; }
MyParentObj.prototype.pDoit = function (mParam) {
console.log('pDoit: ' + mParam + '; ' + this.pParam);
}
return MyParentObj;
})();
var MyObj = (function () {
function MyObj (cParam) { this.cParam = cParam; }
MyObj.prototype = new MyParentObj('p');
MyObj.prototype.cDoit = function (mParam) {
console.log('cDoit: ' + mParam + '; ' + this.cParam);
}
return MyObj;
})();
var aObj = new MyObj('c');
aObj.cDoit(4); // childDoit: 4; c
aObj.pDoit(6); // parentDoit: 6; p
JavaScript has had various module solutions, but always implemented in various libraries. Now Modules are built into ES6.
Basically, modules are for exporting/importing "values" ("first class citizens") from/to modules.
Modules default to "strict" mode, so top-level vars are local (not global/window), top-level this is undefined (not window).
Loading "Scripts":
// ext script
Loading "Modules":
Modules are stored in files. There is exactly one module per file, and one file per module.
The first of two ways to export, which can be used together, but it's recommended not to.
// myModule.js //
export const pi = 3.14159; // The Math handles these...
export function square(x) { return x * x; }
export class MyClass { /* etc */ }
export { someVar, someFunction } // by name
There's a single "default" export, which is anonymous, and there's no trailing semicolon.
export default function () { /* etc */ }
export default class { /* etc */ }
export default someName // something already defined
Many think default exports are something of a code smell.
import { square, diag } from 'myModule'; // named exports
console.log(square(11));
import * as lib from 'myModule'; // load whole module
var m = new lib.MyClass();
import myFuncName from 'myModule'; // from a "default"
myFuncName();
With the success of client-side (CS) JS frameworks, challenges arose as compared to server side (SS):
With the rise of Node, some hope to use it as an opportunity to get the best of both worlds, CS and SS.
The definitions are vague and debateble - sometimes used interchangeably - but these are reasonable:
Isomorphic JS is seamlessly maintaining state regardless where the code is running (CS or SS) even when switching where the code is running.
Universal JS is code that can actually run in both SS (Node) and CS (usually some FE framework).
Some frameworks have "variations" that encompass these concepts, such as Angular Universal, "Server-side Rendering for Angular 2 apps".
Some are built with the express purpose of working this way, such as React.
WC's are native reusable encapsulations of Web interface "components" that include HTML, CSS and JavaScript without "leaking" those into other parts of the document.
They're comprised of:
Other benefits of WC's:
Warning: Much of Web Components is highly experimental and subject to even radical implementation changes at this time.
They allow for creating custom HTML tags and elements. They may also be used apart from WC's.
What differentiates CE's from our current ability to arbitrarily add new tags and elements, is "lifecycle callbacks". These "events" occur when various things happen to the CE.
Custom instances of built-in elements are also possible.
Custom Elements have gone through two major revisions, "v0" and "v1"
Allows for instantiation/rendering of content fragments via JS.
<template id="some-id"><!-- some html --></template>
Similar functionality was often done custom like:
<script type="text/html" id="some-id"><!-- some html --></script>
Apple published a proposal Nov 2017 for Template Instantiation which may change things...
The SD provides the encapsulation for Web Components, keeping its code components isolated from the main DOM.
They're not dissimilar from iframe's which are intended for full documents, while SD is for embedded partial documents and is less restrictive.
Shadow DOM has gone through two major revs, "v0" & "v1"
Used to load a "whole" WC from an HTML file, often with either inline or loaded CSS and JavaScript files.
<link rel="import" href="my_component.html">
Some are thinking that HTML Imports may go away, either to die or be replaced.
While Web Components are an actual (evolving) W3C set of technologies, the concept of "Components" is really taking hold.
Most new (or newly revised) frameworks have some concept of "components" they implement.
See also The Gold Standard Checklist for Web Components github.com/webcomponents/gold-standard/wiki
Since JavaScript is single threaded and subject to its event loop, these "workers" provide ways for background tasks to run, and "threading".
Workers do not affect the UI's responsiveness.
Neither can directly interact with the DOM, have very resticted access, and are limited to communication through a special method.
SW are a network proxy that allow more control over network requests.
They are essential for building offline-first and/or PWA (Progressive Web Apps) and handling things like periodic background syncs, inconsistent network connectivity, push notifications, smart caching, and the like.
They in essence replace the App Cache API that had a number of flaws.
Service Workers can use localhost but otherwise must use HTTPS.
SW's are too complex to offer any simple examples.
SW's are supported by Chrome, Firefox, Safari 11.1 (iOS Safari 11.3), and Edge 17.
WW are general purpose "threads" in which to run computationally intensive processes outside of the main UI thread.
Given JS's "run-to-completion" event loop, "blocking" code is quite easy to create; so run it in a WW.
They come in two flavors, Dedicated and Shared:
WW's are well supported (even IE11) but Shared WW, Chrome, FF and "Chromium Edge" only.
// main code
var myWorker = new Worker('my-task.js');
myWorker.addEventListener('aMessage', function(e) {
console.log('from worker: ', e.data);
}, false);
myWorker.postMessage(messageObj); // Start worker & pass message
// in my-task.js
self.addEventListener('aMessage', function(e) {
self.postMessage(e.data); // this just returns message
}, false);
Brace yourself, webassembly is ... here!
There's more that are considered expiremental.
It's supported in Chrome, Firefox, Safari 11, and even Edge 15 and Node! (Usually behind a flag)
Demo of UE using WebGL2: Epic Zen Garden (you'll need browser WebGL)
Instead of an object having to construct it's dependencies, you provide them by passing them in. It's another inversion of control.
While this can happen manually, often in frameworks it's handled by an Object Builder.
It makes the code more modular by reducing "coupling". Tight coupling is a code smell.
It helps a lot with testing because you can pass in a mock object during a test, whereas if the object had to ask for it's dependency you'd have to intercept to provide the mock.
var MyParentA = (function () { /* A stuff */
return MyParentA; })();
var MyParentB = /* like MyParentA but does "B stuff" */
var MyObjA = (function () { // non-DI
MyObjA.prototype = new MyParentObjA(); return MyObj; })();
var MyObjB = /* like MyObjA but uses new MyParentObjB(); */
var MyObj = (function (parentObj) { // DI
MyObjA.prototype = new parentObj();
return MyObj; })();
var objA = new MyObjA(); // non-DI
var objB = new MyObjB(); // non-DI, same code but diff function
var diObjA = new MyObj(MyParentA); // DI
var diObjB = new MyObj(MyParentB); // DI, same code, same function
Lead Wed Developer at @meetmiles