Skip to main content

Prototypal Inheritance

[[Prototype]] vs __proto__ vs .prototype in Javascript

A simplified overview of JavaScript prototypes and prototypical inheritance.

[[Prototype]]

  • [[Prototype]] 是 Javascript 中所有对象都具有的隐藏私有属性,它保存着对对象原型的引用。[[Prototype]] is a hidden private property that all objects have in Javascript, it holds a reference to the object’s prototype.

  • An object’s prototype is the object that an object inherits or descends from. 对象的原型是对象继承或派生的对象。

  • In the following diagram the object son descends from father, so father is the prototype of son. That means the hidden [[Prototype]] property of son points to father.

hidden private property

__proto__

  • __proto__Object.prototype 的一个属性,它公开对象的隐藏 [[Prototype]] 属性并允许您访问或修改它。您不应该使用它,因为它已被弃用。
function Person(name) {
this.name = name;
}

const p = new Person('Jack');
console.log('__proto__ =', p.__proto__)
console.log('p =', p)

__proto__

  • 访问对象原型的现代方法是使用 Object.getPrototypeOf(obj)。您还可以使用 Object.setPrototypeOf(obj, prototype) 修改对象的原型。
let father = { name:'aa' };
let son = {};

Object.setPrototypeOf(son, father);
console.log("son's prototype getPrototypeOf =", Object.getPrototypeOf(son));
console.log("son's prototype __proto__ =", son.__proto__);
console.log(Object.getPrototypeOf(son) === son.__proto__); // true

Object.setPrototypeOf

.prototype

  • .prototype 是一个几乎所有函数都具有的特殊属性,仅在将函数作为构造函数调用时使用。说几乎所有是因为使用简洁语法定义的箭头函数和方法没有 .prototype 属性,不能用作构造函数。.prototype is a special property that almost all functions have that is only used when a function is invoked as a constructor function. I say almost all because arrow functions and methods defined using the concise syntax do not have .prototype properties and cannot be used as constructors.

  • .prototype 属性包含对对象的引用,当构造函数用于实例化或创建新对象时,.prototype 被设置为新对象的原型

  • 当构造函数ObjectFactory实例化一个对象objobj的内部隐藏属性[[Prototype]]ObjectFactory.prototype 指向的是同一个对象(obj’s [[Prototype]] property references the same object as ObjectFactory.prototype。这意味着ObjectFactory.prototype 中定义的任何属性或方法都可以被 obj 访问。

function ObjectFactory() {
this.property = `Hi, I'm a property`;
}

let obj = new ObjectFactory();

console.log(typeof ObjectFactory.prototype); // object
console.log(ObjectFactory.prototype.isPrototypeOf(obj)); // true
console.log(obj.__proto__ === ObjectFactory.prototype); // true
console.log(obj.__proto__ === ObjectFactory.prototype === Object.prototype); // false
console.log(Object.getPrototypeOf(ObjectFactory.prototype) === Object.prototype); // true
console.log(Object.prototype.isPrototypeOf(ObjectFactory.prototype)); // true

ObjectFactory.prototype.prop = `I'm a property of ObjectFactory.prototype`;

console.log(obj.__proto__.prop); // I'm a property of ObjectFactory.prototype
console.log(obj); // ObjectFactory {property: "Hi, I'm a property"}
console.log(obj.prop); // I'm a property of ObjectFactory.prototype
var obj1 = new Object();
var obj2 = {};
var obj3 = { a: 1 };

console.log( Object.getPrototypeOf( obj1 ) === Object.prototype ); // 输出:true
console.log( Object.getPrototypeOf( obj2 ) === Object.prototype ); // 输出:true
console.log( Object.getPrototypeOf( obj3 ) === Object.prototype ); // 输出:true
info
  • prototype是所有构造函数都具有的属性;[[Prototype]]是所有对象都具有的隐藏私有属性;当构造函数ObjectFactory实例化一个对象objobj的内部隐藏属性[[Prototype]] 指向 obj的原型,即ObjectFactory.prototype

  • ObjectFactory.prototype 的原型,即Object.prototype。也就是说,构造函数.prototype的原型 是 Object.prototype

  • 使用构造函数Object 或 字面量{ } 创造的对象,其原型是Object.prototype

Understanding Prototypal Inheritance In JavaScript

要理解原型继承,我们需要理解这三个关键概念,即:继承(inheritance)、原型(prototype)、原型链(prototype chain)

  • 继承是指一个对象可以访问另一个对象的属性和方法的过程。
  • 一个对象、它的原型和它的原型的原型,一直到最后一个原型之间的对象引用链称为原型链。
const AppleInc = {
name: "Apple",
logo: "Apple fruit",
operating_system: "Apple Software",
on () {
console.log("Turning on your " + this.name + " device")
},
off () {
console.log("Turning off your " + this.name + " device")
}
}

const iPhone = {
name: "iPhone",
operating_system: "ios"
}

console.log(iPhone)
// sets AppleInc to be the prototype of the iPhone object.
iPhone.__proto__ = AppleInc // NEVER DO THIS IN REAL-LIFE. ONLY FOR DEMONSTRATION PURPOSE
console.log(iPhone) // logs iPhone with AppleInc as its prototype.
console.log(iPhone.on()) // Turning on your iPhone device
console.log(iPhone.off()) // Turning off your iPhone device
console.log(iPhone.name)

__proto__

  • 结合this查看原型链
info

this 首先指向发起调用的对象,因为它可以在 iPhone 对象中找到name property,所以它指向该对象。但它无法在 iPhone 对象中找到store property,因此它指向其原型并在那里查找该属性并找到它。

  • All data types in JavaScript have a prototype object, JavaScript 中的根对象Object.prototypeObject.prototype的原型对象是null

An Easy Guide To Understanding Constructors In JavaScript

constructors

  • 构造函数 实际上是普通的 JavaScript 函数。它们的特别之处在于它们总是与 JavaScript 中一个非常强大的运算符一起调用,称为 new 运算符。
function Person () {
this.firstname = "Lawrence"
this.lastname = "Eagles"
this.occupation = "Software Developer"
this.gender = "male"
}
Person(); // 不使用new则就是普通函数调用
console.log('此时this指向全局对象 --->', window.firstname); // 此时this指向全局对象 ---> Lawrence