&引用;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

在阅读了本文以及随后的“JavaScript:好的部分”之后,我将致力于成为一名更好的JavaScript开发人员。然而,我还有一个问题要问。我通常实现如下方法:

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理念做什么。