blob: ea64ec409ae3e74a9c37e5dc7aa08e3cc605c2cf [file] [view]
# JavaScript Overview for V8 Developers
This document provides a high-level overview of how JavaScript works, focusing on concepts that are relevant for understanding V8's implementation.
## Primitives vs. Objects
JavaScript has two main categories of values:
### 1. Primitives
Immutable values that are passed by value.
* `undefined`, `null`, `boolean` (`true`/`false`), `number`, `string`, `bigint`, `symbol`. (Spec names are capitalized, but JS `typeof` returns lowercase strings).
* In V8, small integers (Smis) are stored directly in the pointer word, while other primitives are allocated on the heap (e.g., `HeapNumber`, `String`).
### 2. Objects
Mutable collections of properties, passed by reference.
* Any value that is not a primitive is an object (including arrays and functions).
* In V8, objects are represented by `JSObject` and its subclasses.
* **Note**: JS also has primitive wrapper objects (e.g., `new String('foo')`), which are actual objects and not primitives. Be careful not to confuse them with the primitive values!
## How V8 implements prototypes
JavaScript uses a **prototypal inheritance** model. Every object has a hidden link to another object called its **prototype** (internal `[[Prototype]]`).
### Prototype Chain
* When you access a property on an object, JavaScript first looks for it on the object itself.
* If not found, it looks at the object's prototype, and then the prototype's prototype, forming a **prototype chain**.
* The chain ends when it reaches `null` (typically `Object.prototype.__proto__` is `null`).
### `Foo.prototype` vs `foo.__proto__`
* `Foo.prototype` is a property of the **constructor function** `Foo`. It is the object that will be used as the prototype for instances created with `new Foo()`.
* `foo.__proto__` is a property of the **instance** `foo`. It points to the prototype object that `foo` inherited from.
* If `foo = new Foo()`, then `foo.__proto__ === Foo.prototype`.
```dot
digraph G {
rankdir=TB;
node [shape=record];
edge [];
Foo [label="Constructor: Foo"];
Foo_Proto [label="Foo.prototype"];
foo [label="Instance: foo"];
Obj_Proto [label="Object.prototype"];
null_node [label="null"];
Foo -> Foo_Proto [label=".prototype"];
Foo -> foo [label="new Foo", style=dashed];
foo -> Foo_Proto [label="[[Prototype]]"];
Foo_Proto -> Obj_Proto [label="[[Prototype]]"];
Obj_Proto -> null_node [label="[[Prototype]]"];
}
```
### `__proto__` and V8 Implementation
* `__proto__` is an accessor property (getter/setter) on `Object.prototype` that exposes the internal prototype link.
* Modern JavaScript recommends using `Object.getPrototypeOf()` and `Object.setPrototypeOf()` instead of `__proto__`.
* In V8, the prototype is stored in the `Map` of the object. Changing the prototype of an object changes its map!
## ES6 Classes
ES6 classes are primarily **syntactic sugar** over JavaScript's existing prototype-based inheritance.
```javascript
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
```
Under the hood, this is equivalent to:
```javascript
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise.');
};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(this.name + ' barks.');
};
```
## File Structure
* `src/objects/js-objects.h`: Definitions for JavaScript objects.
* `src/objects/map.h`: Definitions for Maps (hidden classes) which store prototype links.