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!
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;
})();
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.
Related
In traditional OOP language, we usually use private/public to implement data encapsulation.
In Javascript, there is no private or public anymore; someone told me; by using closure, the data encapsulation can be implemented. I am wondering how and what's the behind logic?
You can encapsulate data in a 'Class' (no real class before JavaScript 6) this way
var yourClass = function() {
var privateProp = 'sometext'; //private prop
this.prop = 1; //public
this.getPrivateProp = function() {
return privateProp; //access to your private prop with a closure
}
}
var test = new yourClass();
//when you use 'new', everything in 'this' is returned in your object.
//'privateProp' is not in 'this' but 'getPrivateProp' is.
//You got your private data not directly accessible from outside.
test.prop; // 1
test.privateProp;//undefined
test.getPrivateProp();// 'sometext'
Actually isn't creating actual private members.
Check the following code:
function A() {
var doStuff1 = function() { };
this.doStuff2 = function() {
doStuff1();
};
};
var instance = new A();
instance.doStuff2();
Since doStuff2 is declared and added to this, it's part of A instance while doStuff1 is declared as a local variable within the constructor function, and thus, it's only accessible using closures within the same constructor.
BTW I don't like this pattern since it works great when you don't use prototypal inheritance.
Let's say I want to use prototypes:
function A() {
var doStuff1 = function() {}; // ??????
};
A.prototype = {
doStuff2: function() {
// How do I access a local variable defined
// in the constructor function local scope?
}
};
So, the whole pattern works in simple scenarios where you don't want to use prototypal inheritance.
Also, this pattern won't work in scenarios where you want to use Object.create(...), since there's no constructor function at all...
// Constructor isn't ever called...
var instance = Object.create(A.prototype);
So, how you would implement this kind of encapsulation in JavaScript? For now isn't possible, but many libraries and frameworks have opted-in to use naming conventions to let developers know what's consumed by the library/framework code and what's intended for use in actual third-party developments.
For example:
function A() {
};
A.prototype = {
___doStuff1___: function() {},
doStuff2: function() {
this.___doStuff1___();
}
};
After all, this is a naming convention, where members which are sorrounded by ___ are considered private or not intended for third-party developers.
Other libraries/framework use $$ (f.e. Angular, $$privateMember).
Since there is a benefit to use prototype for methods if you need to create lots of them, do you get the same effect and benefit when you create an object with methods that close over "this" in the constructor function?
See the following code:
(function(){
var Planet = function(){
var self = this;
var API = {
publicInterfaceMethodA:function(){
self.privateProtoMethodA();
},
publicInterfaceMethodB:function(){}
};
return API;
};
Planet.prototype = {
privateProtoMethod:function(){ },
privateProtoMethodA:function(){ },
privateProtoMethodB:function(){ },
privateProtoMethodC:function(){ },
privateProtoMethodD:function(){ },
privateProtoMethodE:function(){ }
};
var mars = new Planet();
}());
Let's say I have 100 "private" methods on the prototype, for every instance I create I only want to expose these few public api methods, but I want to retain the benefit of using the prototype for internal methods so that I dont "copy" 100 methods to "this" for every instance created.
From what I can see, this is not how people usually do it, am I missing something here or do you get the same benefit without returning "this" in the constructor and exposing the entire prototype?
Thanks
When I started to develop seriously in JS, I also often used the var self = this;, because I was used to it from the various jQuery tutorials and I also tried your approach and others to simulate private methods.
Personally I don't like both anymore.
While it is true that mars is not an instance of Planet, this is - in my opinion - not a real problem, because I normally test for api features and not that often if an object is an instance of a certain constructor.
To private methods/members: when your projects grows and becomes larger you probably want to start to do unit tests. If you e.g. have 100 private methods and only 10 public ones, creating good unit test can become really problematic. For unit test you would like to test as less dependencies as possible.
Thats why I changed my mind and preferred to create a clear documentation of api with jsdoc using the annotation to mark methods/members if they are private instead of not over really hiding them.
Sometime it could also be useful not just be able to replace public methods base on the situation, but also private ones.
There are for sure valid situations for your approach, but if you just use it to protect the function from misuse, you probably should think about it.
To the var self = this;: As long as someFunction.bind(element) does not create performance problems I prefer to use bind (there is a polyfill for older browsers). With that you can avoid deep nesting of e.g. callbacks and you don't need to keep in mind that you need to use self where the expected keyword would be this.
How about something like this?
(function(){
var Planet = function(){
var self = this;
self.constructor.methods = {
A: function(){ console.log('Constructor Method A called'); },
B: function(){ },
C: function(){ },
D: function(){ },
E: function(){ }
};
var API = {
publicInterfaceMethodA: function(){
return self.constructor.methods.A.call(this);
},
publicInterfaceMethodB: function(){}
};
return API;
};
var mars = new Planet();
mars.publicInterfaceMethodA();
}());
The methods are attached to the Planet function and then called by the mars instance.
I'm writing a chrome extension which needs to interact with a subtree of bookmarks. There are a lot of interactions with this subtree, so I'm abstracting this logic into an object literal, like so:
var contextStore = {
'root_id': undefined,
'setup': function() {...}, // populates root_id
'add': function(name) {...}, // uses root_id
'remove': function(name) {...}, // uses root_id
// ... etc ...
};
contextStore.setup(); // only once.
contextStore.add("foo");
contextStore.add("bar");
// ... etc
So far, so good.
The trouble I'm having is caused by the asynchronous Chrome APIs (and my lack of JS-fu). To wit:
var contextStore = {
'root_id': undefined,
'setup': function() {
chrome.bookmarks.getTree(function(tree) {
// do some work to find a given folder in bookmarks.
// now I want to save that folder's id for access in other methods.
// Fail: 'this' refers to chrome.bookmarks.getTree.
this.root_id = computed_thing; // doesn't work!
});
}
// ... etc ...
};
My question is:
How do I go about accessing members of the enclosing object literal from inside the various Chrome API method callbacks?
I looked at using the module pattern, but it doesn't seem to change things, and it's not like this code is going to be consumed by anything outside the extension.
You need to store a reference to the this which points to the contextStore object;
var contextStore = {
'root_id': undefined,
'setup': function() {
var that = this; // Store reference here.
chrome.bookmarks.getTree(function(tree) {
that.root_id = computed_thing; // does work!
});
}
// ... etc ...
};
This is equivalent to doing;
var contextStore = {
'root_id': undefined,
'setup': function() {
chrome.bookmarks.getTree(function(tree) {
contextStore.root_id = computed_thing; // does work!
});
}
// ... etc ...
};
However you gain the benefit of not reusing contextStore everywhere.
The this keyword can be bound to different things depending on how you call it. I'm not a javascript expert, but there is a good explanation at A List Apart.
The solution is to bind explicitly when calling the function using either my_function.apply(obj, [args]), my_function.call(obj, args) (call now) or pre-bind the function for calling later: my_function.bind(obj).
As a python programmer, being explicit probably makes you happy :-)
Matt's answer is eventually the better approach, as it is even more explicit, succinct and doesn't require the function to be called or prepared in a certain way. I just thought I would try to explain what was going on.
Prototypal object creation in JavaScript is claimed to be powerful (I hear it is efficient and if used correctly very expressive). But for some reason I find that it trips me up much more often than it helps me.
The main problem I have with patterns for object creation involving prototype is that there is no way to bypass the need for this. The main reason is that objects that are anything beyond very primitive, for example objects that populate themselves through asynchronous API calls, this breaks down due to change of scope.
So, I use prototypal object creation for objects that I know everything about from the beginning.
But for objects that need to do for example API calls to keep themselves up to date I completely skip prototype and use straight up object literals.
When I feel the need for extending one of these objects, I have used parasitic inheritence:
var ROOT = ROOT || {};
ROOT.Parent = function () {
var self = {
func1 : function () {
alert("func1")
};
}
return self;
};
ROOT.Child = function () {
var self = ROOT.Parent(); // This is the parasitizing
self.func2 = function () {
alert("func2")
};
return self;
};
var myChild = ROOT.Child();
myChild.func1(); // alerts "func1"
myChild.func2(); // alerts "func2"
Using this pattern, I can reuse the code for func1 in the ROOT.Child object. However if I want to extend the code in func1 I have a problem. I.e if I want to call the code in the parents func1 and also my own func1 this pattern presents a challenge. I cannot do this:
ROOT.Child = function () {
var self = ROOT.Parent();
self.func1 = function () {
alert("func2")
};
};
Since this will completely replace the function. To solve this I have come up with the following solution (which you can also check out here: http://jsfiddle.net/pellepim/mAGUg/9/).
var ROOT = {};
/**
* This is the base function for Parasitic Inheritence
*/
ROOT.Inheritable = function () {
var self = {
/**
* takes the name of a function that should exist on "self", and
* rewires it so that it executes both the original function, and the method
* supplied as second parameter.
*/
extend : function (functionName, func) {
if (self.hasOwnProperty(functionName)) {
var superFunction = self[functionName];
self[functionName] = function () {
superFunction();
func();
};
}
},
/**
* Takes the name of a function and reassigns it to the function supplied
* as second parameter.
*/
replace : function (methodName, func) {
self[methodName] = func;
}
};
return self;
};
/**
* "Inherits" from ROOT.Inheritable
*/
ROOT.Action = function () {
var self = ROOT.Inheritable();
/**
* I intend to extend this method in an inheriting object
*/
self.methodToExtend = function () {
alert("I should be seen first, since I get extended");
};
/**
* I intend to replace this method in an inheriting object
*/
self.methodToReplace = function () {
alert("I should never be seen, since I get replaced.");
};
return self;
};
/**
* "Inherits" from ROOT.Action.
*/
ROOT.Task = function () {
var self = ROOT.Action();
self.extend('methodToExtend', function () {
alert("I successfully ran the extended code too.");
});
/**
* I know it is completely unecessary to have a replace method,
* I could just as easily just type self.methodToReplace = function () ...
* but I like that you see that you are actually replacing something.
*/
self.replace('methodToReplace', function () {
alert("I successfully replaced the \"super\" method.");
});
return self;
};
var task = ROOT.Task();
task.methodToExtend(); // I expect both the "base" and "child" method to run.
task.methodToReplace(); // I expect only the "child" method to run.
Ok, so I should ask a question. Am I completely off target here or am I on to something? What are the apparent drawbacks?
No, you're not off target. But you did not invent that wheel also. That type of ECMAscript inheritance became very famous with Doug Crockfords book Javascript: The good parts.
It is a nice pattern and uses closures nicely to keep things private and protected. However, it's still up to you which patterns you prefer (plain prototypal inheritance, pseudo-classical).
With ES5 and new possiblitys like Object.create() and Object.defineProperties(), Object.freeze() to name a few, we also have good ways to have protection and privacy with a more prototypal approach. Personally, I still prefer and like the pseudo classical way, using closures to do stuff.
The caveat still might be function-calls overhead which you generally can avoid using a plain prototypal inheritance. We need to make a whole lot more calls to get things properly done (if things grows). Still, closures are considered to be a little memory greedy and probably be a reason for leaks if we use them sloppy or forget to clean up references here and there. I don't have any reference for this now, but I strongly believe that the latest js engines are not much slower using closures like a lot.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I've been developing jQuery plugins for quite some time now, and I like to think I know how to design one well by now. One issue keeps nagging me though, and that is how to deal with private functions in a powerful yet elegant manner.
My plugins generally look something like this:
(function($) {
$.fn.myplugin = function(...) {
...
// some shared functionality, for example:
this.css('background-color', 'green');
...
};
$.fn.mypluginAnotherPublicMethod = function(...) {
...
// some shared functionality, for example:
this.css('background-color', 'red');
...
};
}(jQuery));
Now my question is: how to neatly DRY up that shared functionality? An obvious solution would be to put it in a function within the plugin's namespace:
var fill = function($obj, color) {
$obj.css('background-color', color);
};
Although this solution is effective and nicely namespaced, I really dislike it. For one simple reason: I have to pass it the jQuery object. I.e. I have to call it like this: fill(this, 'red');, while I would like to call it like this: this.fill('red');
Of course we could achieve this result by simply putting fill into jQuery.fn. But that feels very uncomfortable. Imagine having ten plugins developed based on this approach and each plugin putting five of those 'private' functions into the jQuery function namespace. It ends up in a big mess. We could mitigate by prefixing each of these functions with the name of the plugin they belong to, but that doesn't really make it more attractive. These functions are supposed to be private to the plugin, so we do not want to expose them to the outside world at all (at least not directly).
So there's my question: does anyone of you have suggestions for how to get the best of both worlds. That is; plugin code being able to call 'private' plugin functions in a way similar to this.fill('red') (or this.myplugin.fill('red') or even this.myplugin().fill('red') etc.), while preventing jQuery function namespace pollution. And of course it should be light-weight, as these private functions might be called very frequently.
UPDATE: Thanks for your suggestions.
I especially like David's idea of defining an object type that holds the 'private' functions and wraps a jQuery object. The only problem with it is that it still disallows me from chaining 'private' and 'public' functions. Which was big reason to want a syntax like this.fill('red') to begin with.
I ended up with a solution which I consider not tremendously elegant, but appealing to the 'best of both worlds' cause:
$.fn.chain = function(func) {
return func.apply(this, Array.prototype.slice.call(arguments, 1));
};
Which allows for constructs like:
this.
find('.acertainclass').
chain(fill, 'red').
click(function() {
alert("I'm red");
});
I cross-posted my question in other places, which also collected some interesting responses:
http://forum.jquery.com/topic/jquery-plugin-design-pattern-common-practice-for-dealing-with-private-functions
http://groups.google.com/group/jquery-en/browse_thread/thread/fa8ccef21ccc589a
One thing first: if you would like to call something like this.fill('red'); where this is an instance of jQuery, you have to extend the jQuery prototype and make fill() "public". jQuery provides guidelines for extending it's prototype using so called "plugins" that can be added using $.fn.fill, which is the same as jQuery.prototype.fill.
In jQuery callbacks, this is often a reference to the HTML Element, and you can't add prototypes to those (yet). That is one of the reason why jQuery wraps elements and return jQuery instances that can be easily extended.
Using the (function(){})(); syntax, you can create and execute "private" javascript on the fly, and it all disappears when it's done. Using this technique, you can create your own jQuery-like syntax that wraps jQuery into your own private chainable object.
(function(){
var P = function(elem) {
return new Private(elem);
};
var Private = function(elem) {
this.elem = jQuery(elem);
}
Private.prototype = {
elem: null,
fill: function(col) {
this.elem.css('background',col);
return this;
},
color: function(col) {
this.elem.css('color', col);
return this;
}
}
$.fn.myplugin = function() {
P(this).fill('red');
};
$.fn.myotherplugin = function() {
P(this).fill('yellow').color('green');
};
})();
$('.foo').myplugin();
$('.bar').myotherplugin();
console.log(typeof P === 'undefined') // should print 'true'
This way, the P stands for your own toolbox of "private" functions. They won't be available anywhere else in the code or in the jQuery namespace unless you attach them somewhere. You can add as many methods as you like in the Private object, and as long as you return this, you can also chain them jQuery-style as I did in the example.
How about (within the plugin's scope):
var fill = function ()
{
(function (color)
{
this.css ('backgrorund-color', color);
//.. your stuff here ...
}).apply (this, arguments);
}
$.fn.myplugin = function ()
{
fill ('green');
}
That way, fill will retain the jQuery context you're in, and is still private to your plugin
Amended: the above is incorrect w.r.t. scoping, Try the following instead:
var fill = function (color)
{
if (!$this) return; // break if not within correct context
$this.css ('backgrorund-color', color);
//.. your stuff here ...
}
$.fn.myplugin = function ()
{
var $this = $(this); // local ref to current context
fill ('green');
}
You might want to take a look at how the jQuery UI Widget Factory is implemented.
The basic approach is like this:
(function($){
$.fn.myplugin = function(method)
{
if (mp[method]) // map $('foo').myplugin('bar', 'baz') to mp.bar('baz')
{
return mp[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
else if (typeof method === 'object' || ! method)
{
return mp.init.apply(this, arguments); // if called without arguments, init
}
else
{
$.error('Method ' + method + ' does not exist on $.myplugin');
}
};
// private methods, internally accessible via this.foo, this.bar
var foo = function() { … };
var bar = function() { … };
var private = { // alternative approach to private methods, accessible via this.private.foo
foo : function() { … },
bar : function() { … }
}
var mp = { // public methods, externally accessible via $.myplugin('foo', 'bar')
init : function( options )
{
return this.each(function()
{
// do init stuff
}
},
foo : function() { … },
bar : function() { … }
};
})(jQuery);
Unfortunately, "private" methods (or any property for that matter) can never be called with a "this" prefix in javascript. Anything which is called like this.myFunc(myArgs) must be publicly available.
And "private" methods can only be called from within the scope in which they were defined.
Your original solution is the only one that will work. Yes, it's a pain having to pass in this, but there's no more verbosity than there would be if your impossible request was possible:
this.fill('green');
//or
fill(this,'green');
As you can see, they both take up exactly the same number of characters in your code.
Sorry to say, but you're stuck with this as a solution, unless you want to create a new namespace and make them not private - which is simply going to add to the amount of code you need to write, i.e. what you indirectly called "not directly exposed":
this.myplugin.fill('green');
...is more verbose, thus kind of defeats the purpose.
Javascript is not like other languages, there are no "private" members per-se, only members accessible within closures, which can sometimes be used in a similar way to private members, but is more of a "workaround", and not the "real-deal" private members you are looking for.
It can be difficult to come to terms with this (I often struggle), but don't try to mould javascript into what you understand from other languages, take it for what it is...