I'm having a bit of trouble figuring out the best way to implement this.
I want a module that has a constructor that takes in an argument that stores it for later use within the module.
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
}
ModuleB.prototype = function() {
//private stuff/functions
function someMethod() {
moduleA.doSomething();
}
//public api
return {
someMethod : someMethod
};
}();
In some other file
//ModuleA defined elsewhere
var moduleA = new ModuleA();
//...
var module = new ModuleB(moduleA);
module.someMethod();
Now above in someMethod, moduleA is undefined, and this, is the global window object. Can someone explain how I would get access to moduleA? I don't understand what happens to this.moduleA = moduleA; after the constructor. I'm not really a javascript developer so if I'm using the wrong pattern here or something, feel free to chime in.
You are very close, but you're missing something important in your definition of someMethod.
EDIT: is is easier to tell what works and what doesn't if you change the name of the module property in ModuleB:
var ModuleA = function() {}
ModuleA.prototype = (function () {
return {
someMethod: function () {
return 'foo';
}
};
}());
var ModuleB = function(moduleA) {
this.innerModule = moduleA;
}
ModuleB.prototype = (function () {
return {
doStuff: function () {
return this.innerModule.someMethod();
}
};
}());
var moduleA = new ModuleA();
var moduleB = new ModuleB(moduleA);
console.log(moduleB.doStuff()); // prints "foo"
http://jsfiddle.net/mN8ae/1/
Try this:
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
}
// Simplifying your code, what was missin is the "this" keyword accessing the moduleA
ModuleB.prototype.someMethod = function() {
this.moduleA.doSomething();
};
var module1 = new ModuleB({
doSomething: function(){
alert('i do something');
}
});
module1.someMethod();
You would need to use call/apply to execute the method for given context.
try this code (I have modified your code)
var ModuleB = function(moduleA) {
this.moduleA = moduleA;
};
ModuleB.prototype = function() {
//private stuff/functions
function someMethod() {
this.doSomething();
}
//public api
return {
someMethod : someMethod
}; }();
var ModuleA=function(){
this.doSomething=function(){
alert('moduleA Method');
}; };
var modA=new ModuleA(); var modB=new ModuleB(modA);
modB.someMethod.call(modA);
Thanks!
Related
I am new to IIFE and trying to implement namespace in JavaScript on a Siungleton JavaScript class:
I have a JavaScript class (say main class):
var myIIFE = (function () {
var x = null;
//constructor function
var myIIFE = function() {
var a = new IIFE.InsideIIFE(); //says not a constructor
}
myIIFE.prototype = {
//some methods
}
function createIstance() {
return new myIIFE();
}
return {
getInstance: function() {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
Then I have another JavaScript namespaced class:
myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
I want to create an object of myIIFE.InsideIIFE in myIIFE, and this is throwing me an error:
myIIFE.InsideIIFE is not a constructor
Am I doing something wrong? Or if this is a correct approach then what changes I should make.
I tried using new this.InsideIIFE() and just InsideIIFE, but non of them worked.
edit:
From my analysis, I understand that myIIFE (the parent) is an object as it return an object at:
return {
getInstance: function() {
//method body
}
}
There are many issues with this code, let's try to run it in our heads, from the start:
var myIIFE = (function () {
....
})();
This results in myIIFE being an object, to be precise, this object:
{
getInstance: function() {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
}
So, then I assume, you do
myIIFE.getInstance()
Which tries to return new myIIFE();
It runs into myIIFE() and tries to do this:
new IIFE.InsideIIFE();
I assume you meant to write
new myIIFE.InsideIIFE();
because IIFE is not defined it anywhere in the code you provided.
Let's see what is myIIFE.insideIIFE
var myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
First of all you start with var, which is wrong, because myIIFE is already defined and you are just adding a new property to it. so it should be simply
myIIFE.InsideIIFE = (function() {
var inside = function() {}
inside.prototype = { //some methods }
return inside;
});
and it should work.
In general, it seems by your code, like you have not grasped the whole "constructor function" concept very well. I would suggest you take look at the following links, they should help.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
I write a module in nodejs ,which Test.js ,code blow
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = Test;
and then, in B.js
var Test = require('./services/Test');
var test = new Test();
console.log(test.foo());
unfortunetly, I got "undefined method foo",
anyone who can Tell me what happended? thanks so much
Check your file location it should be in services directory.
function Test() {
this.key = 'value';
}
Test.prototype.foo = function () { return 'foo'; }
module.exports = new Test();//Test;
var test = require('./services/Test');
console.log(test.foo());
You can export the new object of Test class. try this.
Or you can use ES6 JavaScript that great.
In Test.js try moving the module.exports to before you define the prototype functions.
As below:
function Test() {
this.key = 'value';
}
module.exports = Test;
Test.prototype.foo = function () { return 'foo'; }
I've got a module object that I want to clone and then override a function for.
var Module1 = (function () {
var hello = "hi there!";
return {
sayHello : function () {
console.log(hello);
}
}
})();
var Module2 = (function (old) {
var my = {}, key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
my.sayHello = function () {
console.log(old.hello + " again");
}
return my;
}(Module1));
Is there a way to access the 'private' variable 'hello' from the submodule? Calling Module2.sayHello() (on the code shown above) prints undefined again!.
No, you can't.
You can add
getHello : function () {
return hello;
}
into Module1's return block, in this case you expose a public function which reuturn's Module1's private vairable hello.
Is it possible to have private properties in a model? Like the locally declared variables in a (constructor) function, not attached to this, but declared locally and visible only by whatever is defined in the (constructor)function.
Example without BB View:
function MyView(aModel){
var $internalInput = $('<input>');
this.render: function($where){
$internalInput.val(aModel.get('SomeProperty'));
$where.append($('<div class="inputWraper">').append($internalInput));
};
this.toggleReadonly: function() {
toggle $internalInputs readonly attribute
}
...
+ Code to bind input.val to some aModel property(ies) and setup events
...
}
Note that internalInput is not accessible to outside world and aModel is also not accessible (through MyView at least).
So if I want to use Backbone.View to implement the above MyView, how would i do it and keep $internalInput 'private'?
You should be able to achieve private data by passing an IIFE to extend when defining your Backbone objects, rather than just a plain object. For example:
var Thing = Backbone.Model.extend((function () {
var foo = "Private data!";
return {
bar: function () {
console.log(foo);
}
};
})());
You'd better off with
var Thing = Backbone.Model.extend(
{
constructor : function ()
{
var _value = "Private data!";
this.getValue = function ()
{
return _value;
};
this.setValue = function (value)
{
_value = value;
};
}
});
Javascript is fun!
var Thing = (function () {
var number_of_things = 0;
return function (options) {
var value = "Private data!";
return new ( Backbone.Model.extend({
constructor: function constructor () {
number_of_things += 1;
},
getValue: function getValue () {
return value;
}
}) )();
};
}());
I'm a little concerned by the fact that every instance of this "Thing" is also a subclass, in the OOP lingo.
In the context of using Broserify.js with Backbone (and really any above medium project) I found the following way to have private vars and functions:
myView.js
'use strict';
var config = require('../config.js'),
private_var = 'private variable',
my_private_fn = function() {
...
};
module.exports = Backbone.Model.extend({
initialize: function() {
this.my_public = 'public variable');
console.log('This is my' + this.my_public);
console.log('This is my' + my_private);
},
});
The idea to take here is go with Browserify :P
The simplest way is the following:
...
initialize:function(properites){
// Init the logic with private and public methods/variable
this.logic.initFirst(this);
// Use public methods
this.logic.doSomething();
},
logic:{
initFirst:function(modelOrView){
// Do not continue if already initiated
if( this.instance !== undefined ) return;
// Write all logic here
this.instance = (function(logic, modelOrView){
// Private variables
var private = "private";
// Public methods
logic.doSomething = function(){
console.log(private, modelOrView);
};
// Private methods
function hidden(){
}
}(this, modelOrView));
}
},
I currently know two ways to construct singletons in JavaScript. First:
var singleton = {
publicVariable: "I'm public",
publicMethod: function() {}
};
It is perfect except that it does not have a constructor where I could run initialization code.
Second:
(function() {
var privateVariable = "I'm private";
var privateFunction = function() {}
return {
publicVariable: "I'm public",
publicMethod: function () {}
}
})();
The first version does not have private properties nor does it have a constructor, but it is faster and simpler. The second version is more complex, ugly, but has a constructor and private properties.
I'm not in a need for private properties, I just want to have a constructor. Is there something I am missing or are the two approaches above the only ones I've got?
function Singleton() {
if ( Singleton.instance )
return Singleton.instance;
Singleton.instance = this;
this.prop1 = 5;
this.method = function() {};
}
Here is my solution with closures:
function Singleton() {
Singleton.getInstance = (function(_this) {
return function() { return _this; };
})(this);
}
Test:
var foo = new Singleton();
var bar = Singleton.getInstance();
foo === bar; // true
If you are just looking for a place to initialise your singleton, how about this?
var singleton = {
'pubvar': null,
'init': function() {
this.pubvar = 'I am public!';
return this;
}
}.init();
console.assert(singleton.pubvar === 'I am public!');
Simple and elegant.
var singleton = new function() { // <<----Notice the new here
//constructorcode....
this.publicproperty ="blabla";
}
This is basically the same as creating a function, then instantly assiging a new instace of it to the variable singleton. Like var singleton = new SingletonObject();
I highly advice against using singletons this way in javscript though because of the execution order is based on where in the file you place the object and not on your own logic.
What about this?
var Singleton = (function() {
var instance;
// this is actual constructor with params
return function(cfg) {
if (typeof instance == 'undefined') {
instance = this;
this.cfg = cfg;
}
return instance;
};
})();
var a = new Singleton('a');
var b = new Singleton('b');
//a === b; <-- true
//a.cfg <-- 'a'
//b.cfg <-- 'a'
I make it an actual Singleton with static functions and no this like so:
class S {
//"constructor"
static init() {
//Note: Since it's a singleton, there's no "this" instance.
//Instead, you store variables directly on the class.
S.myVar = 7;
}
static myOtherFunc() {
alert(S.myVar);
}
}
//Immediately call init() to make it the "constructor".
//Alternatively, you can call init() elsewhere if you'd
//like to initialize it at a particular time.
S.init();
//Later:
S.myOtherFunc();
S.myVar = 10;