&引用;JavaScript:好的部分-如何实现原型方法?
在阅读了本文以及随后的“JavaScript:好的部分”之后,我将致力于成为一名更好的JavaScript开发人员。然而,我还有一个问题要问。我通常实现如下方法:&引用;JavaScript:好的部分-如何实现原型方法?,javascript,methods,prototype,Javascript,Methods,Prototype,在阅读了本文以及随后的“JavaScript:好的部分”之后,我将致力于成为一名更好的JavaScript开发人员。然而,我还有一个问题要问。我通常实现如下方法: function MyClass(){ this.myData = 43; this.getDataFromObject = function(){ return this.myData; } } MyClass.prototype.getDataFromPrototype = functio
function MyClass(){
this.myData = 43;
this.getDataFromObject = function(){
return this.myData;
}
}
MyClass.prototype.getDataFromPrototype = function(){
return this.myData;
}
var myObject = new MyClass();
console.log(myObject.getDataFromObject());
console.log(myObject.getDataFromPrototype());
function secretFactory() {
const secret = "Favor composition over inheritance [...]!"
const spillTheBeans = () => console.log(secret)
return {
spillTheBeans
}
}
const leaker = secretFactory()
leaker.spillTheBeans()
我在这篇文章的基础上的假设是getDataFromObject更快(在调用期间,而不是在对象创建期间),因为它节省了对原型的间接寻址,但它的内存效率也更低,因为每个对象都有自己的函数对象实例。如果这已经是错误的,请纠正我,你可能可以停止阅读这里
其他:文章和书籍都推荐这样的风格:
function MyClass(){
this.myData = 43;
this.getDataFromObject = function(){
return this.myData;
}
}
MyClass.prototype.getDataFromPrototype = function(){
return this.myData;
}
var myObject = new MyClass();
console.log(myObject.getDataFromObject());
console.log(myObject.getDataFromPrototype());
function secretFactory() {
const secret = "Favor composition over inheritance [...]!"
const spillTheBeans = () => console.log(secret)
return {
spillTheBeans
}
}
const leaker = secretFactory()
leaker.spillTheBeans()
(引用文章,这本书还没有ES6,但思想是相似的)
我的问题是:
const leaker1 = secretFactory()
const leaker2 = secretFactory()
console.log(leaker1.spillTheBeans === leaker2.spillTheBeans) // false
我不是很想避免每个对象都有自己的每个方法的实例吗?这在这里可能无关紧要,但如果spillTheBeans更复杂,我创建了大量对象,每个对象都有一万两千个其他方法
如果是这样,什么是“傻瓜零件”-解决方案?我的假设是:
const spillStaticBeans = () => console.log("Tabs rule!")
const spillInstanceBeans = (beans) => console.log(beans)
function secretFactory() {
const secret = "Favor composition over inheritance [...]!"
return{
spillStaticBeans,
spillInstanceBeans: () => spillInstanceBeans(secret)
}
}
const leaker1 = secretFactory()
const leaker2 = secretFactory()
leaker1.spillStaticBeans()
leaker2.spillInstanceBeans()
console.log(leaker1.spillStaticBeans === leaker2.spillStaticBeans) // true
console.log(leaker1.spillInstanceBeans === leaker2.spillInstanceBeans) // false
spillInstanceBeans方法仍然不同,因为每个实例都需要自己的闭包,但至少它们只包装了对相同函数对象的引用,该函数对象包含所有开销
但是现在我必须把每个方法名写两到三次。更糟糕的是,我用公共spillStaticBeans和spillInstanceBeans函数将名称空间弄得乱七八糟。为了缓解后者,我可以编写一个元工厂模块:
const secretFactory = (function(){
const spillStaticBeans = () => console.log("Tabs rule!")
const spillInstanceBeans = (beans) => console.log(beans)
return function() {
const secret = "Favor composition over inheritance [...]!"
return{
spillStaticBeans,
spillInstanceBeans: () => spillInstanceBeans(secret)
}
}
}())
这可以像以前一样使用,但是现在方法隐藏在闭包中。然而,它变得有点混乱。使用ES6模块,我还可以将它们保留在模块范围内,而不导出它们。但这是一条路吗
还是我一般都弄错了,JavaScript的内部函数表示解决了所有这些问题,实际上没有问题
我的假设是,getDataFromObject
比getDataFromPrototype
调用更快,因为它节省了对原型的间接寻址
不。发动机非常擅长间接优化原型。对于同一类的实例,instance.getDataFromPrototype
总是解析为相同的方法,引擎可以利用这一点。有关详细信息,请参阅
我不是很想避免每个对象都有自己的每个方法的实例吗?这在这里可能无关紧要
对。在大多数情况下,它实际上是无关紧要的。因此,使用您喜欢的任何样式的方法编写您的对象。只有在实际测量性能瓶颈时,才能重新考虑创建多个实例的情况
使用ES6模块,我还可以将它们保留在模块范围内,而不导出它们。但这是一条路吗
是的,这是一个明智的解决办法。但是,没有充分的理由将spillInstanceBeans
提取到静态范围,只需将其保留在原来的位置-无论如何,您必须在机密
上创建一个闭包
spillInstanceBeans方法仍然不同,因为每个实例都需要自己的闭包,但至少它们只包装了对相同函数对象的引用,该函数对象包含所有开销
应该注意的是,您只是在复制JavaScript VM内部的工作方式:像spillTheBeans
这样的函数在源代码中出现时只编译一次,即使它有secret
这样的自由变量。例如,在SpiderMonkey中,结果称为»proto function«(不要与prototype混淆)。这些是VM内部的,无法从JavaScript访问
在运行时,函数对象是通过将proto函数的自由变量绑定到当前作用域(其中的一部分)来创建的,这与您的spillInstanceBeans
示例非常相似
话虽如此,使用闭包而不是原型方法和this
总体上创建了更多的函数对象是正确的——从真正的隐私和只读属性中获得的健壮性可能值得一试。提议的样式更多地关注对象而不是类,因此可能会出现无法直接与基于类的设计进行比较的不同设计
如前所述,衡量并重新考虑性能是否在代码(某些部分)中更重要。应该注意的是,JavaScript:好的部分在JavaScript时间尺度上相当古老。我同意,但据我所知,JavaScript只是朝着将其原型特性隐藏在类型和类掩码后面的方向进一步发展,我认为当时的解决方案可能不会改变。这是真的,但
类
机制提供了一些非常重要的东西,如果你真的喜欢创建类结构,我一直使用类结构,新的类语法对我来说非常自然,但我很好奇,在这个场景中,真正的JavaScript开发人员会采用JavaScript理念做什么。