prototype-pattern

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prototype Pattern

原型模式(Prototype Pattern)

The prototype pattern is a useful way to share properties among many objects of the same type. The prototype is an object that's native to JavaScript, and can be accessed by objects through the prototype chain.
In our applications, we often have to create many objects of the same type. A useful way of doing this is by creating multiple instances of an ES6 class.
原型模式(Prototype Pattern)是一种在多个同类型对象之间共享属性的实用方式。原型是JavaScript原生的对象,可通过原型链被其他对象访问。
在我们的应用中,经常需要创建多个同类型的对象。实现这一点的一种实用方式是创建ES6类的多个实例。

When to Use

适用场景

  • Use this when many objects need access to the same methods without duplicating them
  • This is helpful for understanding JavaScript's inheritance model and ES6 classes
  • 当多个对象需要访问相同方法而无需重复定义时使用此模式
  • 这有助于理解JavaScript的继承模型和ES6类

Instructions

使用说明

  • Use ES6 classes to automatically add methods to the prototype
  • Use
    Object.create()
    to create objects with a specific prototype
  • Leverage the prototype chain for inheritance (
    extends
    keyword in ES6 classes)
  • Understand that properties on the prototype are shared and not duplicated per instance
  • 使用ES6类自动将方法添加到原型中
  • 使用
    Object.create()
    创建具有特定原型的对象
  • 利用原型链实现继承(ES6类中的
    extends
    关键字)
  • 理解原型上的属性是共享的,不会在每个实例中重复创建

Details

详细说明

Let's say we want to create many dogs! In our example, dogs can't do that much: they simply have a name, and they can bark!
js
class Dog {
  constructor(name) {
    this.name = name;
  }

  bark() {
    return `Woof!`;
  }
}

const dog1 = new Dog("Daisy");
const dog2 = new Dog("Max");
const dog3 = new Dog("Spot");
Notice here how the
constructor
contains a
name
property, and the class itself contains a
bark
property. When using ES6 classes, all properties that are defined on the class itself,
bark
in this case, are automatically added to the
prototype
.
We can see the
prototype
directly through accessing the
prototype
property on a constructor, or through the
__proto__
property on any instance.
js
console.log(Dog.prototype);
// constructor: ƒ Dog(name, breed) bark: ƒ bark()

console.log(dog1.__proto__);
// constructor: ƒ Dog(name, breed) bark: ƒ bark()
The value of
__proto__
on any instance of the constructor, is a direct reference to the constructor's prototype! Whenever we try to access a property on an object that doesn't exist on the object directly, JavaScript will go down the prototype chain to see if the property is available within the prototype chain.
The prototype pattern is very powerful when working with objects that should have access to the same properties. Instead of creating a duplicate of the property each time, we can simply add the property to the prototype, since all instances have access to the prototype object.
Since all instances have access to the prototype, it's easy to add properties to the prototype even after creating the instances.
Say that our dogs shouldn't only be able to bark, but they should also be able to play! We can make this possible by adding a
play
property to the prototype.
The term prototype chain indicates that there could be more than one step. Indeed! So far, we've only seen how we can access properties that are directly available on the first object that
__proto__
has a reference to. However, prototypes themselves also have a
__proto__
object!
Let's create another type of dog, a super dog! This dog should inherit everything from a normal
Dog
, but it should also be able to fly. We can create a super dog by extending the
Dog
class and adding a
fly
method.
js
class SuperDog extends Dog {
  constructor(name) {
    super(name);
  }

  fly() {
    return "Flying!";
  }
}
We have access to the
bark
method, as we extended the
Dog
class. The value of
__proto__
on the prototype of
SuperDog
points to the
Dog.prototype
object!
It gets clear why it's called a prototype chain: when we try to access a property that's not directly available on the object, JavaScript recursively walks down all the objects that
__proto__
points to, until it finds the property!
假设我们要创建多只狗!在我们的示例中,狗的能力不多:它们只有一个名字,并且会吠叫!
js
class Dog {
  constructor(name) {
    this.name = name;
  }

  bark() {
    return `Woof!`;
  }
}

const dog1 = new Dog("Daisy");
const dog2 = new Dog("Max");
const dog3 = new Dog("Spot");
注意这里
constructor
包含
name
属性,而类本身包含
bark
属性。使用ES6类时,所有定义在类本身的属性(本例中的
bark
)都会自动添加到
prototype
中。
我们可以通过访问构造函数的
prototype
属性,或任何实例的
__proto__
属性直接查看
prototype
js
console.log(Dog.prototype);
// constructor: ƒ Dog(name, breed) bark: ƒ bark()

console.log(dog1.__proto__);
// constructor: ƒ Dog(name, breed) bark: ƒ bark()
构造函数的任何实例上的
__proto__
值,都是对构造函数原型的直接引用!每当我们尝试访问对象上不存在的属性时,JavaScript会沿着原型链向下查找,看该属性是否在原型链中可用。
当处理需要访问相同属性的对象时,原型模式非常强大。我们无需每次都重复创建属性,只需将属性添加到原型中,因为所有实例都可以访问原型对象。
由于所有实例都能访问原型,即使在创建实例后,我们也可以轻松地向原型添加属性。
比如我们的狗不仅要会吠叫,还要会玩耍!我们可以通过向原型添加
play
属性来实现这一点。
原型链这个术语意味着可能存在多个层级。确实如此!到目前为止,我们只看到了如何访问
__proto__
直接引用的第一个对象上的属性。但原型本身也有
__proto__
对象!
让我们创建另一种狗——超级狗!这种狗应该继承普通
Dog
的所有特性,还能飞行。我们可以通过扩展
Dog
类并添加
fly
方法来创建超级狗。
js
class SuperDog extends Dog {
  constructor(name) {
    super(name);
  }

  fly() {
    return "Flying!";
  }
}
我们可以访问
bark
方法,因为我们扩展了
Dog
类。
SuperDog
原型上的
__proto__
值指向
Dog.prototype
对象!
现在就明白为什么它被称为原型了:当我们尝试访问对象上不存在的属性时,JavaScript会递归遍历
__proto__
指向的所有对象,直到找到该属性为止!

Object.create

Object.create

The
Object.create
method lets us create a new object, to which we can explicitly pass the value of its prototype.
js
const dog = {
  bark() {
    return `Woof!`;
  },
};

const pet1 = Object.create(dog);
Although
pet1
itself doesn't have any properties, it does have access to properties on its prototype chain! Since we passed the
dog
object as
pet1
's prototype, we can access the
bark
property.
Object.create
is a simple way to let objects directly inherit properties from other objects, by specifying the newly created object's prototype. The new object can access the new properties by walking down the prototype chain.
The prototype pattern allows us to easily let objects access and inherit properties from other objects. Since the prototype chain allows us to access properties that aren't directly defined on the object itself, we can avoid duplication of methods and properties, thus reducing the amount of memory used.
Object.create
方法允许我们创建一个新对象,并可以显式指定其原型的值。
js
const dog = {
  bark() {
    return `Woof!`;
  },
};

const pet1 = Object.create(dog);
虽然
pet1
本身没有任何属性,但它可以访问原型链上的属性!由于我们将
dog
对象作为
pet1
的原型传入,因此可以访问
bark
属性。
Object.create
是一种让对象直接从其他对象继承属性的简单方式,只需指定新创建对象的原型。新对象可以通过遍历原型链访问这些属性。
原型模式让我们能够轻松地让对象访问和继承其他对象的属性。由于原型链允许我们访问未直接定义在对象本身的属性,因此我们可以避免方法和属性的重复,从而减少内存占用。

Source

来源

References

参考资料