links: JS MOC
Pillar 1: Scope and Closure
The organization of variables into units of scope(functions, blocks) is one of the most foundational characteristics of any language; perhaps no other characteristic has a greater impact on how programs behave.
Scopes are like buckets, and variables are like marbles that go into a bucket. The scope model of a language is determined by which color marbles go in which matching-color buckets.
Scopes nest inside each other, for any give expression or statement, only variables at that level of scope nesting or in higher/outer scopes are accessible, variables from inner/lower scopes are hidden and inaccessible.
This is how scopes behave in modern languages, which is called lexical scope. The scope unit boundaries, and how variables are organized in them, is determined at the time of program is parsed(compiled). In other words, It’s the author time decision: where you locate a function/scope in the program determines what the scope structure of that part of the program will be.
Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.
JS is lexically scope, though many claim it isn’t, because of two particular characteristics of its model that are not present in other lexically scoped languages.
The first is commonly called as hoisting : when all variables are declared anywhere in a scope are treated as if they’re declared at the beginning of the scope. The other is that var declared variables are function scoped, even if they appear inside a block.
Neither hoisting, nor function-scoped var are sufficient to back the claim that JS is not lexically scoped. let/const have a peculiar error behavior called the “Temporal Dead Zone” (TDZ) which results in observable but unusable variables. Though TDZ can e strange to encounter, It’s also not an invalidation of lexical scoping. All of these are just unique parts of the language that should be learned and understood by all JS devs.
Closure is a natural result of lexical scope when the language has functions as first-class values, as JS does. When a function makes a reference to variables from an outer scope, and that function is passed around as a value and executed in other scopes, It maintains access to it’s original scope variables; this is closure.
Pillar 2: Prototypes
JS is one of the very few languages where you have the option to create objects directly and explicitly, without defining their structure in a class (this is the most loved feature for me).
For many years people implemented the class design pattern on top of prototypes—so-called “prototypal inheritance” — and then with the advent of ES6’s class keyword, the language doubled down it’s inclination toward OO/class-style programming.
But I think that focus has obscured the beauty and power of the prototype system: the ability of two objects to simply connect with each other and cooperate dynamically (during function/method execution) through sharing a this context.
Classes are just one pattern you can build on top of such power. But another approach, in a very different direction, is to simply embrace objects as objects, forget classes altogether, and let objects cooperate through the prototype chain. This is called behavior delegation. I think delegation is more powerful than class inheritance, as a means for organizing behavior and data in our programs.
But class inheritance gets almost all the attention. And the rest goes to functional programming (FP), as the sort of “anti-class” way of designing programs. This saddens me, because it snuffs out any chance for exploration of delegation as a viable alternative.
“classes aren’t the only way to use objects”
Pillar 3: Types and Coercion
The third pillar of JS is most overlooked part of JS’s nature.
The vast majority of developers have strong misconceptions about how types works in programming languages, and especially how they work in JS. A tidal wave of interest in the broader JS community has begun to shift to “static typing” approaches, using type-aware tooling like TypeScript or Flow.
Arguably, this pillar is more important than the other two, in the sense that no JS program will do anything useful if it doesn’t properly leverage JS’s value types, as well as the conversion(coercion) of values between types.
Without learning this pillar, your foundation in JS is shaky and incomplete at best
tags: javascript , fundamentals