Notes on 'You Don't Know JS (Up & Going)'
Notes on ‘You Don’t Know JS (Up & Going)’
Kyle Simpson’s book You Don’t Know JavaScript is an invaluable resource, offering clear and in-depth explanations of many of JavaScript’s complex and confusing concepts. After reading, you’ll have a much clearer understanding of the language and a rebuilt perspective on JS. It’s highly recommended for frontend developers with over a year of experience.
Scope
JavaScript is a Compiled Language
- Tokenizing/Lexing
- Parsing: generates the Abstract Syntax Tree (AST)
- Code generation
Declarations and Assignments
- Variable assignment operation
- LHS: Declare the variable
- Assignment
- LHS: Finds the target for the operation, such as
b
invar b = a
. In non-strict mode, if the variable is not found, it will be created. In strict mode, it will throw a ReferenceError. - RHS: Finds the value of the target, such as
a
invar b = a
. If the target is not found, it will throw a ReferenceError.
Lexical Scope
- JavaScript uses lexical scope (as opposed to dynamic scope like bash scripts)
eval
andwith
can manipulate lexical scope, making optimizations difficult and leading to performance issues.- Scope nesting:
- Global scope
- Function scope
- Anonymous vs. Named (Anonymous functions are harder to debug, can’t be self-invoked, and have lower readability)
- Immediately Invoked Function Expression (IIFE)
- Block scope
try...catch
is also block scope (babel transpiles to ES3/5)
Hoisting
- Declarations are made during the compilation phase, and assignments occur during the execution phase, leading to variable hoisting.
- Function declarations are hoisted before variable declarations.
- Multiple
var
declarations or function declarations with the same name will ignore the previous ones.
Closures
- A closure is when an inner function is called outside of its lexical scope.
- Common uses of closures:
setTimeout
,setInterval
- Event listeners
- Ajax
postMessage
- Web workers
- Any asynchronous or synchronous methods that use callback functions
this
Misconceptions about this
this
refers to itselfthis
refers to the function’s scope
What is this
?
this
refers to the caller of the function (in ascending order of priority):- Default binding (to the global object)
- Implicit binding (to the parent object)
- Explicit binding (
call
,apply
,forEach
, etc.) new
binding:- Creates a new object
- Links the new object to the prototype
- Binds the new object to
this
in the function call - If the function doesn’t return anything else, it returns the new object
- If
call
is passed a primitive value (number, string, boolean), it will be converted to its object form (e.g.,new Number(...)
).
Objects
Built-in Objects
- String
- Number
- Boolean
- Object
- Symbol
- Function
- Array
- Date
- RegExp
- Error
Object Concepts
- Strings, numbers, booleans, etc., are automatically converted to objects when necessary, e.g.,
42.1.toFixed(0)
. - Why does
typeof null === 'object'
?- In JavaScript, if the first three bits of a binary value are all
0
, it is classified as an object. Sincenull
is all0
s, it’s a bug in the language itself.
- In JavaScript, if the first three bits of a binary value are all
- Property names are always strings. Non-string properties are automatically converted to strings.
- However, in ES6,
Map
allows non-string property names. The book suggests they are also converted to strings, but this is questionable.
- However, in ES6,
- Arrays can also have properties and methods, but their
length
does not change. - Cloning an object:
- JSON-safe object:
JSON.parse(JSON.stringify(obj))
Object.assign({}, obj)
- JSON-safe object:
- Property descriptors:
writable
: Whether the property can be modified.configurable
: Whether the property’s descriptor can be changed (irreversible if set tofalse
).enumerable
: Whether the property is enumerable.
- How to make an object immutable?
writable: false
,configurable: false
Object.preventExtensions()
: Prevents adding new properties.Object.seal()
: Seals the object, equivalent toObject.preventExtensions()
+ all propertiesconfigurable: false
.Object.freeze()
: Freezes the object, equivalent toObject.seal()
+ all propertieswritable: false
.
- How to distinguish between
undefined
and a non-existent property?'a' in obj
obj.hasOwnProperty()
- How to check if a property is enumerable?
'a' in obj
obj.propertyIsEnumerable()
Mixing Objects and “Classes”
- JavaScript does not have real classes. The relationship between a class and an instance is abstract and concrete, while JavaScript’s “class” implementation is based on the prototype chain. There is no inheritance or instantiation, only association.
Prototypes
- All normal prototype chains eventually point to the built-in
Object.prototype
. - JavaScript has objects, not classes, making it a truly “object-oriented” language.
-
One of the most abused and misunderstood behaviors in JavaScript is the attempt to emulate classes.
- Modify an object’s prototype:
Object.setPrototypeOf(obj, pObj)
- Check a prototype:
obj.prototype.isPrototypeOf(x)
- Get a prototype:
Object.getPrototypeOf(obj)
Behavior Delegation
- Delegation is simpler than “class.”
- The
Object.create()
syntax is better thanclass
. - The
class
syntax in ES6 is just syntactic sugar, still based on prototypes.
Errata
p57 ES6 Module Syntax
First mistake:
bar.js
function hello(who){
return "Let me introduce:" + who;
}
export hello;
foo.js
// Import hello() from the bar module
import hello from "bar";
// Other code
This syntax is incorrect. When using import
directly, the default export of the target module is imported. The browser will throw an error: Uncaught SyntaxError: The requested module ‘xx.js’ does not provide an export named ‘default’.
Use object destructuring syntax import {hello} from "bar";
if bar.js uses export {hello};
, or export function hello...
.
Three correct syntaxes:
bar.js
function hello(who){
return "Let me introduce:" + who;
}
export {hello};
foo.js
import {hello} from "bar";
bar.js
export function hello(who){
return "Let me introduce:" + who;
}
foo.js
import {hello} from "bar";
bar.js
export default function hello(who){
return "Let me introduce:" + who;
}
foo.js
import hello from "bar";
Second mistake:
module foo from "foo";
The module
keyword does not actually exist.
p80 this
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log(this.a);
}
foo(); // ReferenceError: a is not defined
In fact, it will not throw an error but will output undefined.
p106 Object Property Names
The book says that object property names are always strings, but in ES6, Map
allows non-string property names. The book suggests they are also converted to strings, but this is questionable.