Consider the following:
function windowTest() { }
(function () {
function test() { }
var test1 = new test(); // Works fine.
var test2 = new window["windowTest"](); // Works since windowsTest is declared globally.
var test3 = new window["test"](); // Fails since in an IIFE.
// How can I create a testObj if I only have the string "test"?
})();
Basically, I want to create an object whose function was declared in an IIFE.
The reason
var test3 = new window["test"]();
fails is because test was not declared globally. If you want to access items declared directly within the IIFE, as you know, you can access them by name.
new test();
Another way is to store your function inside of some kind of object then access that object like you did with window. This is almost always the solution to these kinds of problems.
(function() {
var context = {
test: function() {
console.log('new test');
}
};
var test = new context['test']();
})();
The last way uses eval. eval is almost always a really bad idea. Really, it should be avoided unless you're abusing the language just for the sake of interest. But you can use it in this case.
(function() {
function test() {
console.log('new test');
}
var test = eval('new test()');
})();
You can bind your functions to this:
function(){
//your code using
this.test("Hi");
this["test"]("Hi");
}.call({
//function declarations:
test:window.alert,
});
Still an IIFE so it wont work in the global context :
this.test("Hi");//reference Error
Related
Is it possible to invoke a non-global function, in a global function fashion? (i.e. without using a qualifier)
e.g.
var lib = {
notGlobalFn: function(){ /*...*/ }
};
var foobar = function(){
notGlobalFn();
};
foobar();
I can think of three solutions myself (listed below), but I was hoping there would be another solution which didn't use global functions OR this. context OR subfunctions. Are there any other ways to do this? (Or have I put too many restrictions/am I being a pedant?)
My focus is on brevity and being able to define the foobar function, outside of the context of the lib (i.e. so I can define a library, and let people use it in a local context fashion).
Test: http://jsbin.com/denawa/5/edit?javascript,console
Solution #1: - use a subfunction
Rejected because foobar is integrated into the lib.
var lib = function(){
var notGlobalFn = function(){ /*...*/ }
return {
foobar: function(){
notGlobalFn();
}
}
};
lib().foobar()
Solution #2: - set/unset global function
Rejected because global functions are used.
notGlobalFn = lib.notGlobalFn
foobar();
notGlobalFn = undefined
Solution #3: - use context
Rejected because they're using qualifiers.
var foobar = function(){
this.notGlobalFn();
};
foobar.call(lib);
OR
var foobar = function(){
lib.notGlobalFn();
};
foobar();
All in all, if I had to choose one of the above methods, I'd go with Solution #2.
**EDIT**
Another Solution: - use a local variable (extension of Solution #3).
var foobar = function(){
var notGlobalFn = lib.notGlobalFn
notGlobalFn();
};
And Another Solution: - add notGlobalFn to 'this' (I didn't think this would work).
function init(scope){
scope.notGlobalFn = lib.notGlobalFn
}
var foobar = function(){
init(this)
notGlobalFn()
};
This is the solution I ended up going with. Not sure why this is getting downvoted/closed, no-one has asked for clarification!
function init(scope){
scope.notGlobalFn = lib.notGlobalFn
}
var foobar = function(){
init(this)
notGlobalFn()
};
I just started using module pattern in JavaScript to declare functional objects, but found it annoying to repeat the Foo.prototype keyword in declaring all those public functions you might need.
So I came up with using some shorthand variable for convenience as follows.
(function(){
var Foo = function(){
alert('created Foo');
}
// shorthand for further creation of public functions
var pro = Foo.prototype;
//public function with shorthand
pro.bar = function(){
//some cool stuff here
}
return window.Foo = Foo;
}());
Question is: is there some reason to prevent me from saving these few characters regarding functionality or some unexpected error or is this safe to do?
This seems to work just fine for the cases I used it in?
As far as I know, prototypes is an object like any other when it comes to modifying it. Keeping a reference to it is absolutely ok
Edit:
It's OK to do so, but is sometimes confusing for that if you have code like this:
var pro='123';
(function () {
var Foo=function () {
alert('created Foo');
};
// shorthand for further creation of public functions
var pro=Foo.prototype;
var x=new Foo();
alert(pro);
})();
alert(pro);
or accidentally write it like this:
var pro='123';
(function () {
var Foo=function () {
alert('created Foo');
};
// use pro without var
pro=Foo.prototype;
var x=new Foo();
alert(pro);
})();
alert(pro);
The former will work properly, just it's confusing when reading the code, the reader need to be aware of that the var pro in the IIFE is not the same pro in the global scope.
The latter may be a terrible error that the pro is reassigned and lost its original value.
So I proposed the code as it's in my original answer because you cannot modify this inside the function.
I think you can do it in this way ..
var Foo=(function () {
function Foo() {
alert('created Foo');
}
// inside the anonymous function `this` is `Foo.prototype`
(function () {
this.bar=function () {
//some cool stuff here
};
}).call(Foo.prototype);
return Foo;
})();
var x=new Foo();
x.bar();
I'm trying to create a function which returns another function. I want separate information when each of the inner function is run, but this isn't happening. I know that explanation is not great, so I've put together a small example.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return that;
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
This outputs 2, 2. What I would like is 2, 4 to be output. I know this isn't explained perfectly, so if it's not clear what I'm trying to achieve, can someone explain why the variable seems to be shared across the two functions?
Thanks
Like this ?
var testFn = function(testVal) {
var test = testVal
return {
getVal: function() {
return test
}
}
};
var ab = testFn (4)
var ac = testFn (2)
console.log(ab.getVal(),ac.getVal()) //4 //2
The problem in your code is this.getVal() / returning this
because 'this' refers to the global scope / Window
You are glubbering with the global namespace and overwriting Window.getVal() , the moment you are setting b = testFn (2)
This results in overwriting as method getVal too because they both refer to the global Object and always share the same method getVal
Therefore they share the same closure and are outputing 2
console.log("The same: " + (Window.a === Window.b)) // true
console.log("The same: " + (a === b)) // true
you can see that if you change it a little:
var testFn = function(testVal) {
var x = {}
return (function(testVal) {
var test = testVal;
x.getVal = function () {
return test;
}
return x
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());//4 2
it suddenly works because it results in 2 different Objects returned (btw you don't even need the outer closure)
console.log("The same: " + (a === b)) // false
Here are the JSbins First / Second
I hope you understand this, I'm not good in explaining things
If theres anything left unclear, post a comment and I'll try to update the answer
This question comes down to the context in which functions are invoked in JavaScript.
A function that is invoked within another function is executed in the context of the global scope.
In your example, where you have this code:
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
})(testVal);
}
The inner function is being called on the global scope, so this refers to the global object. In JavaScript a function executed within another function is done so with its scope set to the global scope, not the scope of the function it exists within. This tends to trip developers up a fair bit (or at least, it does me!).
For argument's sake, lets presume this is in a browser, so hence this refers to the window object. This is why you get 2 logged twice, because the second time this runs, this.getVal overwrites the getVal method that was defined when you ran var a = testFn(4);.
JavaScript scopes at function level, so every function has its own scope:
var x = 3;
function foo() {
var x = 2;
console.log(x);
};
console.log(x); //gives us 3
foo(); // logs 2
So what you want to do is run that inner function in the context of the testFn function, not in the global scope. You can run a function with a specific context using the call method. I also recorded a screencast on call and apply which discusses this in greater detail. The basic usage of call is:
function foo() {...}.call(this);
That executes foo in the context of this. So, the first step is to make sure your inner function is called in the right context, the context of the testFn method.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
}.call(this, testVal);
}
The first parameter to call is the context, and any arguments following that are passed to the function as parameters. So now the inner function is being called in the right scope, it wont add getVal to the global scope, which is a step in the right direction :)
Next though you also need to make sure that every time you call testFn, you do so in a new scope, so you're not overwriting this.getVal when you call testFn for the second time. You can do this using the new keyword. This SO post on the new keyword is well worth reading. When you do var foo = new testFn() you create and execute a new instance of testFN, hereby creating a new scope. This SO question is also relevant.
All you now need to do is change your declaration of a and b to:
var a = new testFn(4);
var b = new testFn(2);
And now console.log(b.getVal(), a.getVal()); will give 2, 4 as desired.
I put a working example on JSBin which should help clear things up. Note how this example defines this.x globally and within the function, and see which ones get logged. Have a play with this and hopefully it might be of use.
The output you get is (2,2) because when you do
var that = this;
what you actually get is the global object (window),
the object that holds all the global methods and variables in your javascript code.
(Note that every variable that is not nested under an object or function is global and
every function that is not nested under an object is global, meaning that functions that are nested under a function are still global)
so, when you set:
var test = testVal;
this.getVal = function() {
return test;
}
you actually set the function "getVal" in the global object, and in the next run you will again set the same function - overriding the first.
To achieve the affect you wanted I would suggest creating and object and returning it in the inner function (as #Glutamat suggested before me):
var testFn = function(testVal) {
return new Object({
getVal: function() {
return testVal;
}
});
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
In this way, in the outer function we create an object with an inner function called "getVal" that returns the variable passed to the outer function (testVal).
Here's a JSBin if you want to play around with it
(thanks to #Glutamat for introducing this site, I never heard of it and it's really cool :D)
This question is simplified version of my old question Adding scope variable to a constructor. Question is simple can I add priv variable to the fu()'s scope without changing the function? (not adding inside of the function block)
Here is fiddle
Here is the code:
fff = function() {
alert('constructed');
//alert(priv);
};
pro = {
pub: 'public'
}
var make = function(fu, pro) {
var priv = 'private';
fu.prototype = pro
return function() {
return new fu();
};
};
var cls = make(fff, pro);
var obj = cls();
alert(obj.pub);
As you can see if you de-comment the
//alert(priv);
line Uncaught ReferenceError: priv is not defined error.
I need a way to redifine the scope of the fu() function object.
I don't see the fu object listed, but I think the answer is "yes", you can add a private variable without changing the "function". Now, I may be missing something, but if I follow you, here is what you want:
var fu = {
DoStuff: function(someVar){
alert(someVar);
}
};
Then later in your code:
fu["NewPrivateVar"] = "something!";
Or in dot notation:
fu.NewPrivateVar = "someting!";
Finally:
fu.DoStuff(fu.NewPrivateVar);
Results in:
"something!"
Is that what you are looking to do?
You can't change the scope of the function by calling it from inside an object or a closure.
You can however add the variable to the scope of the function, i.e. in the global scope:
window.priv = 'private';
That will make the function work without changes, but the variable isn't very private...
I'm a javascript newbie, and I've come up with the following scheme for namespacing:
(function() {
var ns = Company.namespace("Company.Site.Module");
ns.MyClass = function() { .... };
ns.MyClass.prototype.coolFunction = function() { ... };
})();
Company.namespace is a function registered by a script which simply creates the chain of objects up to Module.
Outside, in non-global scope:
var my = new Company.Site.Module.MyClass();
I'm particularly asking about the method by which I hide the variable ns from global scope - by a wrapping anonymous function executed immediately. I could just write Company.Site.Module everywhere, but it's not DRY and a little messy compared to storing the ns in a local variable.
What say you? What pitfalls are there with this approach? Is there some other method that is considered more standard?
You dont need to scope classes like that, its only necessary if you have global variables outside of the class. I use this approach...
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = {
foo: function() {
}
};
Also note that I use a object literal for a cleaner prototype declaration
However if you need to scope global variables then you can do
(function() {
var scopedGlobalVariable = "some value";
MyApp.MyClass = function() {
};
MyApp.MyClass.prototype = function() {
foo: function() {
}
};
})();
Your approach looks fine to me.
However, you can also do this slightly different, by returning the "class" from the self-executing function:
Company.Site.Module.MyClass = (function() {
var MyClass = function() { ... };
MyClass.prototype.foo = function() { ... };
return MyClass;
})();
This strips at least all the ns. prefixes. The namespace function can still be utilized to create the objects, but outside of the self-executing function.