返回

JS 揭秘:探索 constructor、prototype、__proto__、[[Prototype]] 与原型链的神秘世界

前端

constructor

constructor 是一个特殊的属性,指向创建该实例对象的函数。使用 instanceof 运算符可以检查一个实例对象是否由某个构造函数创建。

function Person(name) {
  this.name = name;
}

const person = new Person('John');

console.log(person instanceof Person); // true

prototype

prototype 是一个指向构造函数的 [[Prototype]] 属性的指针,即它的父原型对象。每个构造函数都有一个 prototype 属性,它是一个对象,可以包含属性和方法,这些属性和方法可以被该构造函数创建的所有实例对象继承。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

person.greet(); // Hello, my name is John.

proto

__proto__ 是一个特殊的属性,它指向构造函数的 prototype 属性。可以通过 __proto__ 属性来访问和修改原型对象中的属性和方法。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

console.log(person.__proto__ === Person.prototype); // true

person.__proto__.greet.call(person); // Hello, my name is John.

[[Prototype]]

[[Prototype]] 是一个内部属性,指向构造函数的 prototype 属性。它是原型链中不可见的环节,不能直接访问或修改。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

console.log(Object.getPrototypeOf(person) === Person.prototype); // true

原型链

原型链是一个从实例对象到根原型的对象链。当访问一个实例对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到该属性或方法。如果找不到,则会返回 undefined

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

person.greet(); // Hello, my name is John.

person.__proto__.greet(); // Hello, my name is John.

Object.getPrototypeOf(person).greet(); // Hello, my name is John.

Symbol 是不是构造函数

Symbol 不是构造函数,因为它不能用 new 运算符创建实例对象。

const symbol = Symbol('foo');

console.log(typeof symbol); // symbol

constructor 属性是否只读

constructor 属性不是只读的,可以通过 Object.defineProperty() 方法修改它。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

Object.defineProperty(person, 'constructor', {
  value: Function,
  writable: true,
  configurable: true
});

console.log(person.constructor); // Function

prototype、proto、[[Prototype]] 的区别

  • prototype 是一个指向构造函数的 [[Prototype]] 属性的指针。
  • __proto__ 是一个指向构造函数的 prototype 属性的指针。
  • [[Prototype]] 是一个指向构造函数的 prototype 属性的指针。

原型链继承

原型链继承是 JavaScript 中实现继承的一种方式。当一个构造函数的 prototype 属性指向另一个构造函数的 prototype 属性时,这两个构造函数之间就建立了原型链继承关系。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

function Student(name, major) {
  Person.call(this, name);
  this.major = major;
}

Student.prototype = Object.create(Person.prototype);

const student = new Student('John', 'Computer Science');

student.greet(); // Hello, my name is John.

原型委托

原型委托是 JavaScript 中访问原型对象属性和方法的一种机制。当访问一个实例对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到该属性或方法。如果找不到,则会返回 undefined

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person = new Person('John');

person.greet(); // Hello, my name is John.

person.__proto__.greet(); // Hello, my name is John.

Object.getPrototypeOf(person).greet(); // Hello, my name is John.

总结

  • constructor 是一个指向创建该实例对象的函数的属性。
  • prototype 是一个指向构造函数的 [[Prototype]] 属性的指针。
  • __proto__ 是一个指向构造函数的 prototype 属性的指针。
  • [[Prototype]] 是一个指向构造函数的 prototype 属性的指针。
  • 原型链是一个从实例对象到根原型的对象链。
  • Symbol 不是构造函数。
  • constructor 属性不是只读的。
  • prototype__proto__[[Prototype]] 之间的主要区别在于,prototype 是一个指向构造函数的 [[Prototype]] 属性的指针,__proto__ 是一个指向构造函数的 prototype 属性的指针,[[Prototype]] 是一个指向构造函数的 prototype 属性的指针。
  • 原型链继承是 JavaScript 中实现继承的一种方式。
  • 原型委托是 JavaScript 中访问原型对象属性和方法的一种机制。