【问题标题】:Use case for not declaring a function as a prototype of another custom function?不将函数声明为另一个自定义函数的原型的用例?
【发布时间】:2014-12-28 05:56:13
【问题描述】:

我正试图了解在现有自定义对象中声明 js 函数的正确方法。

例如通常我这样做是为了向我现有的对象添加功能:

function whateverController() {
    this.doSomething = function() {

    }
}

这样做有什么好处?

function whateverController() {
    ...some random code
} 

whateverController.prototype.doSomething = function() { 

}

从我一直在阅读的内容来看,后一个示例是声明这些函数的最佳方式,以避免每次创建新的whateverController 对象时都必须重新创建这些函数。

有人可以提供一个很好的用例吗,尽管我以前的例子更适合我?如果有的话?任何好的阅读链接也会有所帮助!

后一种方法是否被认为是标准的?

【问题讨论】:

标签: javascript jquery object prototype


【解决方案1】:

它有用的一件事是模拟私有方法和成员

JavaScript 没有指定可见性的方法,但有一种方法可以通过使用闭包来作弊。 当你运行一个函数时,它的变量存在于一个闭包中,只要有任何东西对它的引用,它就会存在,但是除非你将它们附加到存在于外部的东西上,否则它们不能被该闭包之外的任何东西看到强>。您的代码没有显示它,但您可以执行以下操作:

function whateverController() {
    // START OF SCOPE
    var privateMember = "secret"; // this acts like a private member.

    function privateMethod() {
        // This function is private.
        // Only other functions declared inside this call can see it.
        // But it can see privateMember, and other private stuff, just fine.
    }
    this.doSomethingPublic = function() {
        // This function is public and privileged.
        // It can see privateMember and privateMethod, and outside functions can see it.
        // This is because you attached it to "this".
    }
    // END OF SCOPE
}
whateverController.prototype.doSomethingElse = function() {
    // This method is public but not privileged.
    // It cannot see privateMember or privateMethod,
    // because they were declared outside its scope. But it CAN
    // see this.doSomethingPublic, because you attached it to this.
}

这样做的缺点是必须在构造函数中声明私有和特权函数。这意味着每次运行构造函数时都会重新创建它们,这对性能不利。但从好的方面来说,他们可以使用这个技巧来创建伪私有的东西,而原型上声明的东西是做不到的。

底线:尽可能将函数放在原型上会更好,但有时有充分的理由将它们放入构造函数中。这不是你应该一直做的事情。

【讨论】:

    【解决方案2】:

    首先,这里的区别只有在你不只是制作单例时才真正重要——或者换句话说,除非你创建一个类的多个实例,否则所有这些都不会很重要,例如:

    var redController = new whateverController();
    var blueController = new whateverController();
    

    现在,如果您正在创建一个对象的多个实例,那么尽可能多地放在类的原型上是可行的方法。原因很简单。如果我们这样做:

    function whateverController() {
        this.doSomething = function() {
            // TODO - do stuff
        }
    }
    
    var redController = new whateverController();
    var blueController = new whateverController();
    var greenController = new whateverController();
    
    redController.doSomething(); // Works fine!
    blueController.doSomething(); // Yup, this too!
    greenController.doSomething(); // Looking good!
    

    它会起作用,但要付出代价:每个new whateverController() 都会创建自己的doSomething。换句话说,您现在拥有三个完全独立的 doSomething 函数。

    想象一下,如果这个类有十几个函数,而你创建了它的几十个实例?它很快就会失控。

    这是原型版本的来源。如果我们将代码更改为:

    function whateverController() {
        // ...some random code
    } 
    
    whateverController.prototype.doSomething = function() { 
        // TODO - do stuff
    }
    
    var redController = new whateverController();
    var blueController = new whateverController();
    var greenController = new whateverController();
    
    redController.doSomething(); // Alright!
    blueController.doSomething(); // Still good!
    greenController.doSomething(); // ...you get the idea ;)
    

    现在不是每个控制器都有自己的doSomething,而是使用原型的doSomething;他们不是每次都创建一个新功能!现在,如果您有一个包含十几个函数的类,您可以创建该类的一千个实例,而您的内存中仍然只有最初的十几个函数。效率更高。

    现在,有 个实例,您可能希望使用第一个版本而不是原型版本。当你想要这样做的时候,简短的版本非常简单:任何时候你绝对需要一个对象有它自己的特定版本的函数。通常你不会遇到这种情况,但是如果你开始在 JavaScript 中使用“私有”变量,你会发现你很快就开始需要它们了。

    不过,请记住,这只有在您计划创建一个对象的多个实例时才真正重要。如果只有一个whateverController,并且永远只有一个,您可以选择更喜欢的版本。毕竟,如果你不创建类的新实例,那么你也不会创建函数的新实例。

    哦,在我忘记之前还有一个想法:通常认为类构造函数以大写字母开头。换句话说,如果不打算将whateverController 用作单例,并且想用它来创建类的实例,那么您应该将其命名为WhateverController

    【讨论】:

    • 在解释差异方面也很有帮助。谢谢。接受 Spooniest 的回答,因为他举了一个很好的例子,说明为什么你会以一种方式而不是另一种方式来做。干杯。
    猜你喜欢
    • 1970-01-01
    • 2012-10-28
    • 2011-08-07
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 2012-07-15
    • 2021-03-17
    • 2020-02-28
    相关资源
    最近更新 更多