【问题标题】:Javascript static/singelton - this vs _this vs object nameJavascript static/singelton - this vs _this vs 对象名称
【发布时间】:2014-11-03 20:34:25
【问题描述】:

这是一个关于性能和最佳实践的问题。

假设我有一个封装了大量辅助方法的js对象。该对象被视为一个静态类,这意味着它永远不会被实例化,它的所有方法基本上都是辅助方法。 使用事件和 jQuery 时,对象的 this 范围不断变化,并且由于它具有相当多的方法,我想知道最佳实践是什么 - 在每个方法的开头将 this 保存到 _this 或简单地使用对象名称MyObject

多年来,当谈到单例/静态对象时,我一直在做这两件事,但我认为必须只有一种最佳实践,现在是时候采用最佳方法了。

我目前的研究表明,使用_this 而不是直接调用MyObject 带来的好处主要是这两个:

  • 如果对象的名称发生变化,_this 将始终有效
  • 可能会更快(尽管还没有看到性能测试结果),因为浏览器保持在相同的范围内,不需要每次都找出MyObject 的范围。

使用MyObject 的优点:

  • 编写的代码更少。
  • 垃圾收集管理? (分配的变量更少)
  • 对于某些开发人员来说可能更具可读性(适用多个this
  • 更容易重构代码,因为MyObject 将始终有效

我想知道是否有一种方法可以全局保存_this(当然只在对象的范围内)并避免在每个方法的开头分配它。如果没有 - 是否还有其他我遗漏的优点/缺点,或者直接调用对象名称是否被认为是不好的做法。

这是一个简化的参考对象(真实对象有更多的方法)。

    var MyObject = {
       init: function() {

         this.registerEvents();
         //other stuff

       },
       registerEvents: function() {

         this.registerOnSomeEvent();
         //registering more events..
         //...

       },

       registerOnSomeEvent: function() {
          var _this = this;
          jQuery('#someid').click(function() {
             _this.doSomething();//option 1
             MyObject.doSomething();//option 2
          });
       },

       doSomething: function() {
         //doing something...
       }
    }

MyObject.init();

感谢您的帮助!

【问题讨论】:

    标签: javascript jquery oop this encapsulation


    【解决方案1】:

    您可以将整个对象封装在一个闭包中来实现这一点,而无需在每个函数上指定_this

    window.MyObject = (function () {
        var self = {
            init: function() {
    
                self.registerEvents();
                //other stuff
    
            },
            registerEvents: function() {
    
                self.registerOnSomeEvent();
                //registering more events..
                //...
    
            },
    
            registerOnSomeEvent: function() {
                jQuery('#someid').click(function() {
                    self.doSomething();//option 1
                    self.doSomething();//option 2
                });
            },
    
            doSomething: function() {
                //doing something...
            }
        };
    
        self.init();
    
        return self;
    })();
    

    【讨论】:

    • 我喜欢这个解决方案,但是由于我们再次使用self 作为对象名称,它与直接调用MyObject 真的有很大不同吗?我的意思是性能方面
    • @Yani 老实说,除非您每秒访问该变量 1000 次甚至数百万次,否则这并不重要。您应该首先优化可读性和减少错误。
    • @Yani 没有有意义的性能差异。与对全局变量的嵌入式引用相比,主要优势在于,使用这种方法,self 无法更改 - 全局变量可能会发生变化。
    • 感谢@EstebanFelix 澄清这一点。
    • 也谢谢@Pointy
    【解决方案2】:

    我认为你的问题是你走了很长一段路,煞费苦心地模仿你应该做的事情。

    const mySingleton = (function () {
        // Instance stores a reference to the Singleton 
        var instance;
        function init() {
            // Singleton
            // Private methods and variables
            var privateVariable = "Im also private";
            var privateRandomNumber = Math.random();
    
            return {
                // Public methods and variables
                publicMethod: function () {
                    console.log( "The public can see me!" );
                },
                publicProperty: "I am also public",
                get randomNumber() {
                    return privateRandomNumber;
                }
             };
             function privateMethod(){
                console.log( "I am private" );
             }
    
         };
         return {
             // Get the Singleton instance if one exists
             // or create one if it doesn't
             get instance() {
                 if ( !instance ) instance = init();
                 return instance;
             }
         };   
    })();
    

    如果你不想使用 this 上下文,永远不要使用继承并且永远不要有多个实例,只是不要将这些东西写为对象上的方法,而是在 @ 中声明的私有方法987654321@(这是一个具有启发性的模块模式,但只有一个实例)

    因为实际上您基本上就是这样做的,但是您透露了所有内容,并且毫无目的地向this 发送了数百次垃圾邮件。 this 不是一个常数的设计。不要这样使用它。

    【讨论】:

    • 你是对的,因为我来自服务器端语言,我试图模仿静态类行为。我不知道可以做你描述的+1。但是,它并没有回答如何处理事件和jQuery,范围发生了变化?
    • 范围永远不会改变。使用这种模式,任何东西都会 100% 的时间引用相同的东西。上下文(this)会改变,但范围不会改变。但是您根本不需要担心 this,因为在这种模式下您根本不会使用它。
    • 如果您还没有,请查看addyosmani.com/resources/essentialjsdesignpatterns/book。它是一本免费的在线书籍,其中详细介绍了(当然)包括显示模块模式在内的 JavaScript 设计模式。
    • @GaryStorey 猜猜我现在要打开什么来检查我是否说了一些愚蠢的话(结果我做到了,单例模式有点不同,我会更新我的答案=)跨度>
    • @Winchestro 感谢您的回答,我之前使用过此模式的稍微不同的版本,但我不确定如何在 jQuery 事件中调用私有/公共方法。你会直接使用mySingleton.methodName()instance.methodName() 吗?
    猜你喜欢
    • 2018-09-24
    • 2013-12-08
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多