Back to V8

JavaScript Overview for V8 Developers

docs/javascript-overview.md

15.0.103.7 KB
Original Source

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.