mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> PR-URL: https://github.com/nodejs/node/pull/65161 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Richard Lau <richard.lau@ibm.com>
3.7 KiB
3.7 KiB
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 JStypeofreturns 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
JSObjectand 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(typicallyObject.prototype.__proto__isnull).
Foo.prototype vs foo.__proto__
Foo.prototypeis a property of the constructor functionFoo. It is the object that will be used as the prototype for instances created withnew Foo().foo.__proto__is a property of the instancefoo. It points to the prototype object thatfooinherited from.- If
foo = new Foo(), thenfoo.__proto__ === Foo.prototype.
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) onObject.prototypethat exposes the internal prototype link.- Modern JavaScript recommends using
Object.getPrototypeOf()andObject.setPrototypeOf()instead of__proto__. - In V8, the prototype is stored in the
Mapof 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.
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:
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.