如何解决在原型上使用闭包有什么缺点吗?
我喜欢使用闭包创建具有私有属性的对象的一般风格。我不确定的是在闭包内或在对象的实际原型上创建原型方法是否更有效。考虑以下示例:
const A = function(a,b) {
this.a = a;
this.b = b;
};
A.prototype = {
add:function() { this.a += this.b; }
};
const B = (function() {
function add() { this.a += this.b; }
return function(a,b) {
return { a,b,add };
};
})();
示例 A 是一个带有原型的传统构造函数。使用它看起来像这样:
var a = new A(1,1);
a.add(); // a.a == 2;
示例 B 是使用闭包的技术。使用它看起来像这样:
var b = B(1,1);
b.add(); // b.a == 2;
我希望 a 的工作方式是 A 的每个实例都有 a 和 b 属性以及一个指向保存 add 方法的原型对象的指针。
我期望 b 的工作方式是 B 的每个实例都有 a 和 b 属性以及指向 add 方法的指针。 B 函数有一个包含 add 方法的闭包。 add 方法仅在定义 B 时定义一次。这似乎是在 JS 中创建“原型”属性和方法的一种不错的方式。有谁知道这是一种创建具有“共享”属性的对象的高效方法,还是使用原型的传统方法的可行替代方案?
解决方法
您的闭包示例对于这种构建器函数风格来说有点不典型,因为它不会在 B
本身中创建任何函数,只是在创建 B
的匿名函数中创建;这意味着它避免了这样做的常见小缺点(每次调用 B
时都重新创建函数)。 (通常“闭包风格”在 B
本身中创建函数,因此它可以直接在执行上下文中使用 a
和 b
,而不是使用 this.a
和 {{1} } 属性。)
我看不出你所做的有任何性能下降。从理论上讲,它会有一个非常小的性能提升(完全除了您观察到的对象字面量比使用 this.b
快得多),因为实例上的方法是自己的属性而不是继承的属性,因此(理论上)它们的查找速度会稍微(因为 JavaScript 引擎会立即在对象上找到它们,而不是在对象本身上找不到它们而不得不去查看原型) .但实际上,我希望任何现代 JavaScript 引擎都能进行优化,这样您就不会从中受益。
我可以看到一些非性能方面的缺点,但没什么大不了的:
-
一切都只是一个对象,因此如果您正在调试一个无关的性能问题并查看堆快照,那么一切都只是
new
而不是Object
或 {{1} } 或A
,这使得使用内存分析器更加困难。我试图通过向它们添加B
属性来获取内存配置文件以对它们进行分类,但它不起作用(无论如何在 Chrome 中)。我认为它使用了对象原型的构造函数。你可以通过给对象一个特定于构造函数的原型来解决这个问题,只是不使用它,但这看起来有点奇怪。 -
要在不使用原型对象的情况下增强对象,您必须改用 mixins,这意味着将所有属性从一个对象复制到另一个对象,这需要更多的工作,并且意味着每个对象都比它们本来的要大如果他们使用原型继承,可能会在低端设备(移动设备等)上造成内存流失。 (或者,使用组合而不是增强,这有单独的论据。)
-
你正在反对这种语言。 JavaScript 的原型性质是其本质的重要组成部分(即使您不使用构造函数而是使用
C
或类似函数)。 JavaScript 引擎旨在擅长优化原型关系。你会做别的事情。可能还不错,只是看起来不太理想。 -
当使用的模式不典型时,其他人更难跟上代码库的速度。使用 JavaScript 的三种典型方式是构造函数(带有原型)、非
constructor
闭包/Object.create
方式(带有原型)和函数式编程。你看到的是前两者的混合。
但是如果您正在解决与对象创建速度相关的特定问题,那么有针对性地使用这种稍微不寻常的模式可能会非常成功。或者您可能只是喜欢它,并乐于接受不利的一面。 :-)
,更好的是,不要使用原型或闭包。只需使用常规函数即可。
const C = (a,b) => ({ a,b });
function add(c) {
c.a += c.b;
}
const c = C(1,1);
add(c); // c.a === 2;
console.log(c); // { a: 2,b: 1 }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。