Javascript static/singelton - this vs _this vs obj

2019-05-06 16:45发布

问题:

This is a question about performance and best practice.

Assuming I have a js object that encapsulates a large number of helper methods. The object is being treated as a static class, meaning it is never instantiated and all its methods are basically helper methods. When using events and jQuery, the object's this scope keeps changing, and since it has a fairly large number of methods I am wondering what is best practice - saving this into _this at the beginning of each method or simply use the object name MyObject.

Over the years I've been doing both, when it comes to singelton/static objects, but I figured there must be just 1 best practice and it's about time to adopt the best approach.

My current research shows that the benefits that come with using _this instead of directly calling MyObject are mainly these two:

  • if the object's name changes, _this will always work
  • May be faster (although haven't seen performance testing results) since the browser stays in the same scope and does not need to find out the scope of MyObject every time.

Pros of using MyObject:

  • Less code to write.
  • Garbage collection management? (less variables to assign)
  • May be more readable for some developers (where multiple this apply)
  • Easier to refactor code since MyObject will always work

I would like to know if there is a way of globally saving _this (only inside the object's scope of course) and avoid assigning it at the beginning of each method. If not - are there other pros/cons that I am missing or is it considered bad practice to call the object name directly.

This is a simplified object for reference (real object has many more methods).

    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();

Thank you for your help!

回答1:

You can encapsulate the entire object in a closure to achieve this without specifiying _this on every function:

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;
})();


回答2:

I think your problem is that you go a very long way of painstakingly emulating something you should do instead.

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;
         }
     };   
})();

If you don't want to ever use the this context, never use inheritance and never have more than one instance just don't write those things as methods on an object, but rather declared, private methods in a singleton pattern (which is a revealing module pattern but with only a single instance)

Because as it is you basically make exactly that but you are revealing everything and you spam this hundreds and hundreds of times completely without any purpose. this isn't a constant by design. Don't use it as such.