Going back to general programming basics. Even after 25 years, I can still learn some new things, or get a precise definition of some terms.
- variables - not typed
- literal values - typed
- operators
- statements are made of: expressions, any reference to a variable or value, or a set of variables and values combined with operators
a = b + 2
2
- literal value expression
b
- variable expression
b * 2
- arithmetic expression
a = b * 2
- assignment expression
b * 2
- standalone expresssion statement: rare because somewhat useless
alert(a)
- call expression: -> Functions
input: use the prompt()
function for simple tasks
var
- language keyword
You should always declare variables before you use it. You only need to declare a variable once for each scope.
Different representations for values are called types in programming terminology Values that are included directly in the source code are called literals. string literals are surrounded by single quotees or double quotes. number and boolean literals are represented as is. More value types: objects, fuinctions, etc
Converting = "Coercion" in programmer jargon
-
explicit coercion:
var a = "42"; Number(42)
-
implicit coercion:
"99.99" == 99.99 ; // true
var b = "42" * 1
-
Implicit coercion is a Controversial Topic.
- Detailed Rules should be learned!
Static Typing == Type Enforcement Dynamic Typing == Weak Typing: Javascript
Constants: often put atthe top of program, ALL_CAPS
as of ES 6: new keywork const
consistent usage of const
enforced by "Strict Mode" use strict
. Similar to static-typing type enforcement
Blocks: standalone general block { a = a + 2; } is not that common in JS
Functions: introduced as tools to break up tasks into reusable pieces, or to organize code arguments = parameters functions can return a value
Scopes: if a scope is netsted in another scope, code inside the innermost scope can access valiables from either scope.
JS built-in types: string, number, boolean, null and undefined, object, symbol (new to ES &6)
a = null; typeof a; // null
- weird bug left in sthe spec for backward compatibility
Oject property access: prefer dot .
to bracket []
¸ shorter and easier to read. Exceptions:
special characters in object key, or when key is accessd via a variable
Actually, types array
and function
are more subtypes of object than proper built-in types
function foo(){return 23;}
typeof foo; // "function" typeof foo(); // "number" typeof foo.bar; // function property, do not use
built-in type methods: var a = "Test"; a.toUpperCase()
(and other methods) works by JS automatically wrapping this string into a String
object and calling a method on that object (boxing, autoboxing?). String
and other object wrappers are called "natives". String, Number, Boolean. (Function)
Truthy and Falsy
specific list of "falsy" values in Javascript
"", 0, -0, NaN
, null, undefined, false`
Any value that is not "falsy" is "truthy". In particular, [], {}, function(){}
Coercion
var a = 42, var b = "42";
a == b; // true because coercion String => Number (not number => string)
a === b; // false`
ES5 Spec The Abstract Equality Comparison Algorithm is relatively straightforward: take a look!
FOr nonprimitive values, like objects and array, ==
and ===
both check whether the referenecs mathc, not anything about the underlying values.
NaN comparisons are always false
var a = 42, var b = "foo";
a < b; // false because coercion String => Number fails, NaN returned, not "42" != "foo"
"42" < "43" // false because lexicographic comparison
Variable names: if not declared with characters from Unicode, then rules are simple. Some reserved words are OK to use as object property names.
Function Scopes:
Hoisting, Metaphorically: when a var
declaration is conceptually "moved" to the top of its enclosing scope.
- variable hoisting should not be used , bad practice
- hoisting function declarations: much more acceptable
Nested Scopes:
when accessing a variable's value in a scope where it's not available: ReferenceError
thrown
let
variable declaration: block scoping. variable is available inside individual block, a pair of { .. }
Very useful for fine-grained structures. Use let inside for/while
loops and if( ..)
statements.
Switch statement: shorter than nested if/else blocks, also: fall-through behavior
Ternary operator: most often used in an assignment: var b = (a > 41) ? "wisdom": "please wait";
Strict mode: use it for all your programs. put it at the top
Functions as values: a function itself can be assigned to a variable
named function expression:
var x = function bar(){}
Closure: simple form:
function makeAdder(x) {
// inner function uses `x` so it has a c"closure over it"
function add(y) {
return x + y
}
return add;
}
returning a function is a key characteristic of a closure
Modules: introduced as revealing module pattern (not as class, not as modules that can be loaded)
this
identifier:
to understand what this
points to, you need to examine how the function in question was called.
There are four rules for how this
gets set, and they're shown in those last four lines of the following snippet.
- A function
foo()
ends up settingthis
- in non-strict mode, to the global object -- so
"global"
is the value found forthis.bar
. - in strict mode,
this
would beundefined
and you'd get an error in accessing thebar
property
obj1.foo()
setsthis
to theobj1
object.foo.call(obj2)
setsthis
to theobj2
object.new foo()
setsthis
to a brand new empty object.
prototypes: mechanism is quite complicated
When you reference a property on an object, if that property doesn't exist, JavaScript will automatically use that object's internal prototype reference to find another object to look for the property on. You could think of this almost as a fallback if the property is missing.
The internal prototype reference linkage from one object to its fallback happens at the time the object is created. The simplest way to illustrate it is with a built-in utility called Object.create(..)
Mechanism is not "class-based inheritance", but "behavior delegation".
Polyfilling:
defnition of a behaviour that is equivalent to new behavior defined in a newer JS standard, and producing a piece of code
that is able to run in older behavoirs. Exmaple: add your own Number.isNaN()
method. Not all features are fully polyfillable.
Transpiling: When new syntax is added to the language, a polyfill cannot help. The betteroption is to use a too that converts newer code into older code equivalents. Older code equivalents of new code are much more convoluted (see spread operator examples).
Transpilers are now de-facto parts of the standard JS development ecosystem and process. The language evolves very fast. Need transpilers to ensure compatibility with modern but not cutting-edge browsers.
Non-Javascript: The DOM and other browser APIs are not part of JS the language. alert()
isn't either. it's also provided by the browser.