Here is my module:
MyModule = (function () {
var myModule = function MyModule(strInput) {
if (false === (this instanceof MyModule)) {
return new MyModule();
}
str = strInput;
}
var str;
myModule.prototype.getStr = function () {
return str;
}
myModule.prototype.test = function () {
var testModule = new MyModule("testInside");
console.log(testModule.getStr());
console.log(str);
}
return myModule;
}());
Here is how I test my module:
document.getElementById("Button").onclick = function () {
var module = new MyModule("input");
module.test();
}
This code returns:
testInside
testInside
to the console.log, but what I expect is:
testInside
input
like I do in c# or java when I build a new class inside the same class.
If you want to keep the str private, you can make it like this:
MyModule = (function () {
var myModule = function MyModule(strInput) {
if (false === (this instanceof MyModule)) {
return new MyModule();
}
var str = strInput;
this.getStr = function () {
return str;
};
this.test = function () {
var testModule = new MyModule("testInside");
console.log(testModule.getStr());
console.log(str);
};
};
return myModule;
}());
In this way the str is in the inner closure, so it's like an instance/object variable in other languages. If you put it in the outer closure it will act like a static/class variable. In both cases, the methods of the myModule object still can access it, but it's not visible from the outside.
str is a variable stored inside the closure that returns MyModule. It is not a property of any object and it is shared between all instances of MyModule.
When you call .test(), you overwrite it.
If you want it to be associated with the object, then put it on the object:
//...
var myModule = function MyModule(strInput) {
// ...
this.str = strInput;
}
//...
myModule.prototype.getStr = function () {
return this.str;
//...
console.log(testModule.getStr());
console.log(this.str);
//...
Related
Suppose I have an html file that has the structure
<script>
let firstClass = new FirstClass();
var secret = 'code';
function FirstClass() {
this.init = function () {
console.log(SecondClass());
}
}
function SecondClass() {
return 'value';
}
</script>
// some html
<script>
firstClass.init(); // should return a value
console.log(secret); // should be undefined
SecondClass(); // should not be accessible
FirstClass(); // should not be accessible
</script>
How do I make sure that only the firstClass.init() is available from the second part of the <script> and not the SecondClass()?
I would like to use anonymous functions, like ;function({})();
Instantiate firstClass inside an IIFE which contains FirstClass, SecondClass, and secret, and only return firstClass from the IIFE:
<script>
const firstClass = (() => {
const secret = 'secret';
function FirstClass() {
this.init = function() {
console.log(SecondClass());
}
}
function SecondClass() {
return 'value';
}
return new FirstClass;
})();
</script>
<script>
firstClass.init(); // should return a value
console.log(
typeof secret,
typeof SecondClass,
typeof FirstClass
);
</script>
Note that you need to use </script>, not <scipt>, and you need to use new when calling the constructor in order to use the properties assigned to this in the constructor.
This snippet should solve your closure needs.
<script>
(function (global) {
const secret = 'code';
function FirstClass() {
this.init = function () {
console.log(SecondClass());
}
return this;
}
const firstClass = FirstClass();
function SecondClass() {
return 'value';
}
global.firstClass = firstClass;
})(window)
</script>
// some html
<script>
firstClass.init(); // should return a value
console.log(typeof secret); // should be undefined
console.log(typeof SecondClass); // should be undefined
console.log(typeof FirstClass); // should be undefined
</script>
var Greeting = (function () {
function Greeting() {
}
Greeting.prototype.greet = function () {
console.log("Hello World!!!");
};
return Greeting;
}());
var obj = new Greeting();
obj.greet()
If I remove return statement it says obj.greet() is not a function.
The return statement is required because you have created a "private" scope.
// GlobalScope: You create a variable named `Greeting`
var Greeting = (function() {
// PrivateScope: You create a function named `Greeting`
function Greeting() {}
// PrivateScope: You create a method on the Greeting prototype
Greeting.prototype.greet = function() {
console.log("Hello World!!!");
};
// PrivateScope: You tell your function to return your "private" scoped `Greeting`
return Greeting;
}());
You can express the same code without having a "private" scope, and then you will not need the return statement.
function Greeting() {}
Greeting.prototype.greet = function() {
console.log("Hello World!!!");
};
var obj = new Greeting();
obj.greet()
I am using JavaScript prototype chaining technique to chain functions as shown below:
var foo = (function () {
function fn(arg) {
if (!(this instanceof fn)) {
return new fn(arg);
}
this.arg = arg;
return this;
}
var func = function (element) {
return fn(element);
};
fn.prototype = {
bar: function () {
return this;
}
}
func.functions = fn;
return func;
}());
I would like to know how to access fn.prototype so I can add more functionality to the foo prototype outside its closure.
If I just simply do as follows, it won't work:
foo.prototype.baz = function () {
alert(this.arg);
}
foo("hello").baz();
However if fn assigned to the foo (func.functions = fn;) as it shown in the foo private closure I can do as follow and it will works:
foo.functions.prototype.baz = function () {
alert(this.arg);
}
foo("hello").baz();
Is there any other way to achieve this?
I think you are un-necessarily overcomplicating this. You can chain by simply doing this:
const foobar = function(){return this} // Initialize a new Object
const foo = text => {
const me = new foobar()
me.text = text
me.bar = a => (alert(me.text+": "+a), me)
return me
}
foo('A').bar('Test').bar('Test chained')
// Update the foobar class with baz
foobar.prototype.baz = function() {alert('BAZ worked!');return this}
foo('B').bar('1').baz().bar('2')
Note: Click Run code snippet to see the output
That's it!
Edit:
You can also do this with ES6 classes like:
class foobar {
constructor(text) {
this.text = text;
}
bar(a) {alert(this.text+": "+a);return this}
}
const foo = text => new foobar(text)
foo('A').bar('Test').bar('Test chained')
// Update the foobar class with baz
foobar.prototype.baz = function() {alert('BAZ worked!');return this}
foo('B').bar('1').baz().bar('2')
I have code similar to this:
(function (global) {
var MyObject = function (arg1, arg2) {
this.publicVar = arg1;
this._internalVar = arg2;
};
MyObject.prototype = {
publicFunc: function (param) {
return param + this._internalVar;
}
};
global.MyObject = MyObject;
}(window));
Can I somehow get UgilfyJS to mangle _internalVar because it is not intended to be used outside of this scope? I know it can be done with closure compiler using advanced compression etc but I'm using anvil to build and uglifyjs to minify.
To protect _internalVar , I tried
(function (global) {
var MyObject = function () {};
MyObject.prototype = (function(){
var _internalVar = 2;
return {
publicVar: 1,
publicFunc: function (param) {
return param +' '+ _internalVar;
}
};
})();
global.MyObject = MyObject;
}(window));
and tried to access
console.log( ( new window.MyObject()).publicVar );
which print 1
console.log( ( new window.MyObject())._internalVar );
which is undefined
console.log( ( new window.MyObject()).publicFunc('value') );
which print value 2
for more information please check http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript
I've got a module that looks like this:
var MyModule = module.exports = function MyModule(opts) {
opts = (opts === Object(opts)) ? opts : {};
if (!(this instanceof MyModule)) {
return new MyModule(opts);
}
for (var key in opts) if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] == opts[key];
}
};
MyModule.prototype.config = {
something:'value'
}
MyModule.prototype.put = function put(info, cb) {
//do stuff
};
However, when I use it like this:
var myModule = require('myModule.js');
myModule.put({test}, function(){
//some callback stuff
});
I get the following error:
TypeError: Object function MyModule(opts) {
opts = (opts === Object(opts)) ? opts : {};
if (!(this instanceof MyModule)) {
return new MyModule(opts);
}
for (var key in opts) if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] == opts[key];
} } has no method 'put'
It appears I have something wrong with my MyModule.prototype.put ?
You wrote :
var myModule = require('myModule.js');
myModule.put({}, function(){
//some callback stuff
});
Here myModule is in fact MyModule, a constructor function. So what you are doing is MyModule.put(), a call to a "static" method of MyModule. MyModule.prototype.put defines an "instance" method so you have to instanciate first :
var MyModule = require('./myModule.js');
var myModule = new MyModule();
// or as you used `if (!(this instanceof MyModule)) { … }`
var myModule = MyModule();
myModule.put({}, function () {});
So basically your code needs just a pair of () to work :
MyModule().put({}, function () {});
// same as
(new MyModule).put({}, function () {});
Récap :
var MyModule = function () {
// Construct object
};
MyModule.staticMethod = function () {
this; // is bound to `MyModule` function object
};
MyModule.prototype.instanceMethod = function () {
this; // is bound to the `MyModule` instance object it’s called from
};
// Usage
MyModule.staticMethod();
var instance = new MyModule();
instance.instanceMethod();
With this code var myModule = require('myModule.js'); your myModule variable looks like a constructor function, not an instance of myModule.
Try instantiating your module first:
var MyModule = require('myModule.js');
var myModule = new MyModule(); // Create an instance of your module.
// Now use it.
myModule.put(/*... your code here ...*/);