Skip to content

Instantly share code, notes, and snippets.

@knbknb
Last active December 10, 2019 09:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knbknb/2c65568f285e67e3eb58818be8097aa4 to your computer and use it in GitHub Desktop.
Save knbknb/2c65568f285e67e3eb58818be8097aa4 to your computer and use it in GitHub Desktop.
YDKJS : You don't know Javascript (book by Kyle Simpson) ed1

Book 1

Into programming

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.

Into Javascript

New concepts specific to Javascript briefly introduced

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.

  1. A function foo() ends up setting this
  • in non-strict mode, to the global object -- so "global" is the value found for this.bar.
  • in strict mode, this would be undefined and you'd get an error in accessing the bar property
  1. obj1.foo() sets this to the obj1 object.
  2. foo.call(obj2) sets this to the obj2 object.
  3. new foo() sets this 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment