实例构造函数原型_使用构造函数和原型创建内存优化的实例

本文探讨了如何利用JavaScript构造函数和原型链来创建内存优化的对象实例。通过将方法移动到原型链,避免了每个实例重复存储相同函数的问题,显著减少了内存占用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实例构造函数原型

If you have been using JavaScript for a while, you would have come across the term “Constructor functions”, which are a fancy way to call a function that will be used as a blueprint to create object instances.

如果您使用JavaScript已有一段时间,那么您会遇到“构造函数”一词,这是调用函数的一种好方法,该函数将用作创建对象实例的蓝图。

In a classical object-oriented language like Java, these blueprints will be classes. ( Even though we have the class keyword in JavaScript, it is not quite the same as their classical object-oriented counterpart. But let’s look at that in a different article at a later time).

在像Java这样的经典的面向对象的语言中,这些蓝图将是类。 (尽管我们在JavaScript中使用了class关键字,但它与经典的面向对象对象并不太相同。但是稍后我们将在另一篇文章中进行介绍)。

In this article, let’s shift our focus towards looking at a way of creating memory-optimized instances using these constructor functions.

在本文中,我们将重点转移到寻找一种使用这些构造函数创建内存优化实例的方法。

场景: (The Scenario:)

To interpret the results of the optimization and to realize a quantifiable metric, let’s assume the following situation:

为了解释优化结果并实现可量化的指标,让我们假设以下情况:

In our web application, we have to create 200 instances of car objects which have the following properties:

在我们的Web应用程序中,我们必须创建200个具有以下属性的汽车对象实例:

  1. Brand

  2. Top Speed

    最高速度
  3. Current Speed

    现在的速度

The cars should also have two methods namely:

这些车还应该有两种方法:

  1. Accelerate

    加速
  2. Brake

    制动

旁注: (A Side Note:)

To quickly gather insights from the “Heap snapshots” in the chrome developer tools, we will be assigning the car instances to the window object.

为了从chrome开发人员工具中的“堆快照”快速收集见解,我们将汽车实例分配给窗口对象。

Also, we chose the number 200, because the effect of the optimization will be significantly visible on the metrics with the increase in the number of instances.

另外,我们选择数字200,因为随着实例数量的增加,优化的效果将在指标上显着体现。

重型足迹车: (The Heavy Footprint Cars:)

Now, let’s start writing some code and let’s name the constructor function as HeavyCar just to differentiate this from the optimized version which we will be looking at later in this article.

现在,让我们开始编写一些代码,并将构造函数命名为HeavyCar ,以区别于优化版本,我们将在本文稍后介绍。

function HeavyCar(brand, topSpeed) {
  this.brand = brand;
  this.topSpeed = topSpeed;
  this.currentSpeed = 0;
  this.accelerate = function () {
    if (this.currentSpeed + 40 <= this.topSpeed) {
      this.currentSpeed += 40;
      console.log(this.currentSpeed);
      return;
    }
    console.log("Already at max speed!!!");
  };
  this.brake = function () {
    if (this.currentSpeed - 40 >= 0) {
      this.currentSpeed -= 40;
      console.log(this.currentSpeed);
      return;
    }
    console.log("Well, you can't stop a car that's already still, can you?");
  };
}
for (let i = 0; i < 200; i++) {
  window[`car-${i}`] = new HeavyCar(`Car Brand - ${i}`, 80 + (i*40));
}

After running the above code, let’s take a heap snapshot to see how much memory the HeavyCars consumed.

运行以上代码后,让我们进行堆快照以查看HeavyCars消耗了多少内存。

Image for post
Heap Snapshot of HeavyCar
HeavyCar的堆快照

Looking at the report, we can infer that each instance of the HeavyCar has a shallow size of 32 bytes accumulating to 6400 bytes (6.4 Kilobytes) for the total 200 instances.

查看报告,我们可以推断出HeavyCar的每个实例的浅层大小为32个 字节 ,总共200个实例累计为6400字节(6.4千字节)

深入了解实例: (A Deeper Look at The Instances:)

If we look at the instances together, we would realize that while the properties of these instances such as brand, topSpeed and CurrentSpeed may contain unique values for each instance, the methods such as accelerate and brake will always have the same logic irrespective of the instance.

如果我们一起查看这些实例,我们将认识到,尽管这些实例的属性(例如brandtopSpeedCurrentSpeed)可能每个实例都包含唯一的值,但无论实例如何, 加速刹车之类的方法始终具有相同的逻辑。

But these methods are being duplicated in each instance, adding up the memory footprints of each instance and in turn increasing the cumulative footprint.

但是这些方法在每个实例中都是重复的,从而增加了每个实例的内存占用量,进而增加了累积占用量。

Image for post
Methods on every instance
每个实例上的方法

关于优化的思想: (A Thought on Optimization:)

From our observation, we can express that if there is a way to make these methods centralized, we could save some memory, which will have a significant reduction in the cumulative footprint.

从我们的观察中,我们可以表示,如果有一种方法可以使这些方法集中化,则可以节省一些内存,这将大大减少累积占用空间。

By centralization, we mean that we have these methods at a single place in memory and reference that point in memory from the instances.

集中化意味着我们将这些方法放在内存中的单个位置,并从实例中引用内存中的该点。

Since Javascript is based on prototypal inheritance, the above suggestion is practically achievable with very little efforts. All we have to do is, add those methods to the constructor function’s prototype and let the instances refer to it from their __proto__ objects.

由于Javascript是基于原型继承的,因此上述建议实际上是可以实现的,只需很少的努力。 我们要做的就是将这些方法添加到构造函数的原型中,并让实例从其__proto__对象中引用它。

轻型足迹车: (The Light Footprint Cars:)

let’s call our optimized constructor function as LightCar. The following would be the code to achieve what we have discussed above:

让我们将优化后的构造函数称为LightCar。 以下是实现我们上面讨论的代码:

function LightCar(brand, topSpeed) {
  this.brand = brand;
  this.topSpeed = topSpeed;
  this.currentSpeed = 0;
}


LightCar.prototype.accelerate = function () {
  if (this.currentSpeed + 40 <= this.topSpeed) {
    this.currentSpeed += 40;
    console.log(this.currentSpeed);
    return;
  }
  console.log("Already at max speed!!!");
};


LightCar.prototype.brake = function () {
  if (this.currentSpeed - 40 >= 0) {
    this.currentSpeed -= 40;
    console.log(this.currentSpeed);
    return;
  }
  console.log("Well, you can't stop a car that's already still, can you?");
};


for (let i = 0; i < 200; i++) {
  window[`car-light-${i}`] = new LightCar(`Car Brand - ${i}`, 80 + (i*40));
}

on taking the heap snapshot with the above implementation, we have the following results:

通过上述实现获取堆快照时,我们得到以下结果:

Image for post
Heap snapshot of LightCar
LightCar的堆快照

As we can see, we have reduced the shallow size per instance from 32 bytes to 24 bytes which has contributed to a significant reduction in cumulative memory footprint. We have managed to bring down the shallow size for the 200 instances from 6.4 Kb to 4.8 Kb.

如我们所见,我们已将每个实例的浅表大小从32字节减少到24字节 ,这有助于显着减少累积内存占用量。 我们设法将200个实例的浅层大小从6.4 Kb减小到4.8 Kb。

As the number of instances increases exponentially, so will the amount of memory that we have managed to salvage through this optimization.

随着实例数量成倍增加,通过此优化我们设法挽救的内存量也将成倍增加。

看一下优化实例: (A Look at The Optimized Instance:)

Now that we have optimized the methods through prototype chaining, let’s have a look at our instances:

现在我们已经通过原型链接优化了方法,下面让我们看一下实例:

Image for post
References to the methods on the Prototype chain
引用原型链上的方法

We can see that now the methods are under __proto__ in every instance and it is important to note that the one’s within __proto__ are not actual copies of the methods itself but a reference to their memory location.

我们可以看到,现在方法在每种情况下都位于__proto__下,需要注意的是__proto__中的方法并不是方法本身的实际副本,而是对其内存位置的引用。

This is the actual reason why we were able to reduce the memory footprint of the instances.

这是我们能够减少实例的内存占用的实际原因。

结论: (Conclusion:)

These sorts of optimizations are often easier to overlook but can cause serious performance issues down the line. Especially if one is working on a data-intensive application, which is the most prominent kind of web applications these days, they are more likely to face a performance hurdle much sooner in the app’s lifespan.

这些优化通常更容易被忽略,但可能会导致严重的性能问题。 特别是如果人们正在处理数据密集型应用程序(这是当今最主要的Web应用程序),则它们更有可能在应用程序的使用寿命中面临性能障碍。

As a rule of thumb, always consider adding your methods to the prototype of the constructor function, to save the hassle of dealing with serious bottlenecks later in production.

根据经验,始终考虑将方法添加到构造函数的原型中,以免在以后的生产中处理严重瓶颈的麻烦。

Thanks for reading my thoughts, cheers :)

感谢您阅读我的想法,欢呼:)

翻译自: https://medium.com/javascript-in-plain-english/creating-memory-optimized-instances-with-constructor-functions-and-prototypes-5249310c96a6

实例构造函数原型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值