I prefer to use functional OOP style for my code (similar to the module pattern) because it helps me to avoid the "new" keyword and all problems with the scope of "this" keyword in callbacks.
But I've run into a few minor issues with it. I would like to use the following code to create a class.
namespace.myClass = function(){
var self = {},
somePrivateVar1;
// initialization code that would call
// private or public methods
privateMethod();
self.publicMethod(); // sorry, error here
function privateMethod(){}
self.publicMethod = function(){};
return self;
}
The problem is that I can't call public methods from my initialization code, as these functions are not defined yet. The obvious solution would be to create an init method, and call it before "return self" line. But maybe you know a more elegant solution?
Also, how do you usually handle inheritance with this pattern? I use the following code, butI would like to hear your ideas and suggestions.
namespace.myClass2 = function(){
var self = namespace.parentClass(),
somePrivateVar1;
var superMethod = self.someMethod;
self.someMethod = function(){
// example shows how to overwrite parent methods
superMethod();
};
return self;
}
Edit.
For those who asked what are the reasons for choosing this style of OOP, you can look into following questions:
Prototypal vs Functional OOP in JavaScript
Is JavaScript's "new" keyword considered harmful?
You can use Zet.js library which will help you with declaring classes in the way you want.
Several questions occur to me, such as why you want to avoid the new operator, and why you want to call functions before they are defined. However, leaving those aside, how about something more like the following?
namespace.myClass = function(){
var somePrivateVar1;
var self = {};
// initialization code that would call
// private or public methods
privateMethod();
publicMethod();
function privateMethod(){}
function publicMethod(){}
self.publicMethod = publicMethod;
return self;
}
I agree with almost every comment or answer provided so far, but to take Tim's answer one step further - he questioned why you'd want to call a method before it was defined, but offered a solution anyway, whereas I'd suggest you shouldn't call before defining (I don't know of any language where calling a method prior to defining it or at least declaring it is considered good practice), so how about:
namespace.myClass = function(){
//declare private vars (and self) first
var self = {},
somePrivateVar1;
//then declare private methods
function privateMethod(){}
//then public/privileged methods
self.publicMethod = function(){};
// THEN (and only then) add your
// initialization code that would call
// private or public methods
privateMethod();
self.publicMethod(); // no error any more
//then return the new object
return self;
}
Is there a particular reason why this would not work for you?
This is the solution I mentioned in the question. Your comments are welcome.
namespace.myClass = function(){
var self = {},
somePrivateVar1;
function init(){
privateMethod();
self.publicMethod();
}
function privateMethod(){}
self.publicMethod = function(){};
init();
return self;
}
Related
Are there any (non-trivial/ugly hack) ways to call a 'private' method from outside a class/module itself?
Please don't ask why I need this.
Just my personal curiosity and trust in power of doing anything in JS :)
function Module () {
var privateMethod = function () {
alert('1');
};
var publicMethod = function () {
privateMethod();
alert(2);
};
return {
pm: publicMethod
};
}
var m = new Module();
m.pm(); // can i call m.privateMethod() here somehow?
DON'T TRY THIS AT HOME
So you've been warned, now look at this (fiddle; I've replaced all the alerts with console.log() for the greater good):
var methodName = 'privateMethod';
var mSource = Module.toString();
var methodPattern = new RegExp(methodName + '\\s*=\\s*function[^]*?\\{([^]+?)\\};');
var privateMethodSource = mSource.match(methodPattern);
var privateMethodRebuilt = new Function([], privateMethodSource[1]);
privateMethodRebuilt();
It's one possible way to do this with HUGE number of restrictions. First, this particular snippet doesn't even try to parse the arguments, assuming that the method in question doesn't need any. Second, you won't be able to access the other private variables defined within the Module (as the code rebuilds only the particular function, not the environment).
Surely, you can take it further - and rebuild the Module itself, making the target method public (for example, by adding the private function into the exposed methods' list). The question is, WHY on Earth do you even think about needing such thing as using the private method outside the module?
I'm using the Object.init pattern in my application. Where within the init i initialize variables attached to the object, for example:
var MyObject = {
init: function() {
this.element = $('.someElement');
this.element.bind('click', this._doSomething.bind(this));
},
_doSomething = function() {
// METHOD WHICH I WILL MANIPULATE THIS.ELEMENT
}
};
What i'm trying to know is, if i have to create some variables inside the method _doSomething, should i attach the variables to the MyObject with this, like this:
this.someVar = 'something';
Or should i use var:
var someVar = 'something';
I think the best way is use this if i will use the someVar in other parts of MyObject, and i should var if i use only in the scope of _doSomething method.
But this is my opinion, i want know the best practice.
Thanks.
Your presumption is correct; use this.myVar for anything with a lifetime longer than one function.
To give you a better idea of how this works, your object can associate a string key like "myVar" with a variable. this.myVar is shorthand for this["myVar"]. Might look a little weird, but that's standard for setting/retrieving JS properties.
However, var myVar declarations are not associated with any one object; they survive for the lifetime of the function. They can be preserved if you have a function inside of a function, but that's not what you were asking about. If you are curious though, look up the term "closures".
The fact you named your function _doSomething, tells me it's a candidate for an IIFE. It's not accessible to the outside and you can interface with your object using foo.init();
Edit: changed listener, as per comment
jsfiddle
var foo = (function(){
// private function
function doSomething() {
// METHOD WHICH I WILL MANIPULATE THIS.ELEMENT
alert('doSomething()');
}
var myObject = {
init: function() {
this.message = 'hello init';
this.element = $('.someElement');
this.element.on('click', function() { doSomething.call(this); }.bind(this));
alert(this.message);
}
};
return myObject;
})();
foo.init();
I've seen people trying to attempt implementation of private methods in JS. However they all have different issues, like this one: JavaScript private methods
I believe my attempt has some problems as well. But other than the overhead and caller is not allowed in strict mode, what are the problems with my implementation?
You can see an working example in jsfiddle: http://jsfiddle.net/rabbit_aaron/oqpen8c8/17/
the implementation is also pasted here:
var CLASS = function () {
this.publicFunctions = {};
this.PROTOTYPE = {};
var _class = function () {
this.constructor.apply(this, arguments);
};
_class.prototype = this.PROTOTYPE;
_class.prototype.validateAccess = CLASS.prototype.validateAccess;
_class.prototype.constructor = function () {};
_class.prototype.publicFunctions = this.publicFunctions;
this.finalClass = _class;
return this;
};
CLASS.prototype.validateAccess = function (caller) {
if (this.publicFunctions[caller] !== caller) {
throw 'Accessing private functions from outside of the scope';
}
return true;
};
CLASS.prototype.setConstructor = function (func) {
this.PROTOTYPE.constructor = func;
};
CLASS.prototype.addPrivateFunction = function (name, func) {
this.PROTOTYPE[name] = function () {
this.validateAccess(this[name].caller);
func.apply(this, arguments);
};
return this;
};
CLASS.prototype.addPublicFunction = function (name, func) {
this.PROTOTYPE[name] = func;
this.publicFunctions[this.PROTOTYPE[name]] = this.PROTOTYPE[name];
return this;
};
CLASS.prototype.getClass = function () {
return this.finalClass;
};
The first thing that comes to mind is that it is pretty simple to do the following in some code that gets loaded later on:
instanceOfSubClass.validateAccess = function (caller) {
return true;
}
This effectively overrides validation. Pretty much all private variable tricks that don't involve using nested scoping to hide variables suffer from this problem. Of course, this is a pretty specific thing to have to know to do, so it depends on what you are trying to protect against. If you just want to protect against yourself in the future, then this might work fine, but if you are publishing a library that will be interacting with code you don't write and you want to ensure that it will always behave properly, then this isn't the way to go.
I believe my attempt has some problems as well.
Yes.
But other than the overhead and caller is not allowed in strict mode
I wouldn't call that a problem, I'd call it a no-go. Strict mode is supposed to be the default mode.
what are the problems with my implementation?
About your approach of making methods "private":
It's easy to circumvent your measures. Like #Austion you can simply override the validateAccess function, but you can also mess with the public publicFunctions object
It's only hiding methods, not fields. Making non-function properties private is often the more relevant goal, as these are containing the (protection-deserving) state of the instance.
It doesn't work in engines that have no Function::toString decompilation (there are a few old ones). Also, it doesn't work for methods that are programmatically created (as closures) and share the same body.
A few bugs in your implementation that are possible to fix:
private methods can't return a value
private methods can't call other private methods, only public methods can call them
this.constructor.apply(this, arguments); is a nice idea to make a settable constructor. However, it a) will fail horribly once you try inheritance (can be fixed by by calling _class.prototype.constructor) and b) corrupts the rule of thumb that fn.prototype.constructor == fn/Object.getPrototypeOf(instance)==instance.constructor.prototype
Remember, true privacy is only possible through the use of closures.
I'm using the introjs library.
See the original code here.
I want to be able to write var = new IntroJs() rather than call the start() method.
How can I achieve that?
Why not simply wrap up the factory that introJs provides and call start on it in your wrapper?
You can do it externally with something like this (untested):
var introJsWrapper = function(targetElm) {
var ijs = introJs(targetElm);
ijs.start();
return ijs;
};
Or you can do that inside a fork of the introJs code by exposing it as a property of the main function, e.g.:
var introJs = function (targetElm) {
if (typeof (targetElm) === 'object') {
// ...
}
introJs.autoStart = function(targetElm) {
var ijs = introJs(targetElm);
ijs.start();
return ijs;
};
Note that in introJs, the main function is just a very thin parameter-testing/changing wrapper already around the internal constructor. Calling it indirectly invokes the constructor. So there is really no need to access this internal constructor function directly, as far as I can see.
Well, this should be it. I assume these are enclosed in a closure since the code seems to imply that there is some internal functions going on. Here's what I gathered. It's not a complete implementation since I don't know how the this when calling new IntroJS gets used in the constructor. All I know is that your prototype functions are operating on some properties.
//internal functions
function _mergeOptions(target){/*implementation*/}
function _introForElement(el){/*implementation*/}
function _goToStep(step){/*implementation*/}
function _exitIntro(target){/*implementation*/}
function _setHelperLayerPosition(nodeList){/*implementation*/}
//constructor
function IntroJs(first){
this._options = {};
this._introChangeCallback;
this._introCompleteCallback;
this._introExitCallback;
}
Just an empty constructor will suffice. As Jan said, it's pretty useless, but if you like the notation...
http://plnkr.co/edit/eFzkKJ14TeaMY44GDxR2
Ok, so basically this solved my problem:
introJs.fn = IntroJs.prototype = {
...
initialize: function() {
return this;
}
...
}
Now, calling introJs().initialize() gives me the library without calling the start() method.
I've got the first file in my code directory as follows
myNamespace.js
var myNamespace = {};
Then my subsequent files can look as one of the two following ways.
first
(function (ns) {
ns.DoStuff = function(){
// do stuff
}
})(myNamespace);
second
myNamespace.DoStuff = function(){
//do stuff
}
So what is the difference between these two methods? Both seem to work for me. Is there a more generally accepted convention?
sorry, still new to javascript
Your first approach will not work. It would create DoStuff on the global object (most likely window). You would need to replace this with ns, after you did that, there is no difference between the two approaches.
The former will have the adventage that you might be able to closure all your application/file related stuff into that outer self-invoking closure function. So you won't clobber the global namespace.
(function (ns) {
var foo = 10,
bar = 42;
ns.DoStuff = function(){
console.log('foo is ', foo, ' and its not available globally');
}
})(myNamespace);
You have an error in your first one, you've used this where I'm pretty sure you meant ns:
ns.DoStuff = function() {
};
Leaving that aside, your first approach tends to be better because you've created a nice little scoping function for yourself, which allows you to have private data and functions available to all of the public methods you create on your namespace, without making them globals. E.g.:
(function(ns) {
function privateFunction() {
}
ns.DoStuff = function() {
privateFunction(); // <=== works fine
};
})(myNamespace);]
privateFunction(); // <=== doesn't work, because it's private
I like doing it that way partially because I have thing against anonymous functions, and so I wouldn't define DoStuff as above, but rather like this:
(function(ns) {
ns.DoStuff = Namespace$DoStuff;
function Namespace$DoStuff() {
}
})(myNamespace);
Now the function I've assigned to myNamespace.DoStuff has a proper name, which helps me out when I'm debugging my code. But that name doesn't pollute the global namespace, which helps me stay sane and avoid conflicts with other code.