I'm using the module-via-anonymous-function-pattern in java-script to have an anonymous function that embodies the whole module and exposes specific public API parts by setting a global property.
I tried several methods of setting such a global property and the second one posted below fails:
window.foo = (function() {
function bar() { this.hello = "world" }
return new bar();
})();
> foo.hello
"world" // OK
vs.
(function() {
window.foo2 = new bar( this.hello = "world" );
function bar() {}
})();
> foo2.hello
undefined // Fail
Why is the second method not creating a proper bar-object?
In your 2nd method:
(function() {
window.foo2 = new bar( this.hello = "world" );
function bar() {}
})();
this is the window, and
new bar(this.hello = "world")
is equal to
window.hello = "world";
new bar(window.hello);
you can check it here
And I think what you want is :
(function() {
window.foo2 = new bar( "world" );
function bar(a) {this.hello = a}
})();
see here
you should try the code below
(function() {
function bar() { this.hello = "world"; };
window.foo2 = new bar();
})();
The problem is the way to use construct an object. Try this two ways.
window.foo2 = new bar();
function bar() {this.hello = "world";};
or
window.foo2 = new bar("world");
function bar(x) {this.hello = x;};
Related
An example of this question is like this
var bar = (function(){
function foo(){
alert("foo");
}
function test(){
var f = "foo";
// I want to run f() to run the function foo
}
})();
If the function is in the global scope I can run it using window["foo"]() or if namespaced window["namespace"]["foo"]() but how can I run it inside like the example? I don't want to use eval().
A much clear example of what I want is like this:
var fns = ['a','b','c'],
bar = (function(){
function a(){
alert("a");
}
function b(){
alert("b");
}
function c(){
alert("c");
}
function test(array){
for(var i;i<array.length;i++){
//I want to run the functions that is on the array
// something like window[array[i]]() if function is in the global scope
}
}
return {
test : test
}
})();
bar.test(fns);
You can create a local object to reference the function, then access its property as you would with your window example.
var bar = (function(){
function foo(){
alert("foo");
}
var obj = {
foo: foo
};
function test(){
var f = obj["foo"];
f();
}
test();
})();
That's as close as you're going to get in a local scope without using eval.
You can create the object OR fn with this operator and make it an function with new constructor.
Creating an object.
https://jsfiddle.net/0Lyrz6rm/6/
var bar = {
foo: function(){
alert("foo");
},
test: function(){
var f = "foo";
return f;
}
}
bar["foo"]();
console.log(bar["test"]());
Another alternate way is to define the function as with constructor and little modification.
https://jsfiddle.net/0Lyrz6rm/4/
var bar = function(){
this.foo = function(){
alert("foo");
};
this.test = function(){
var f = "foo";
return f;
// I want to run f() to run the function foo
}
this.test2 = {
f: "foo"
}
}
var f = new bar();
f["foo"]();
console.log(f.test());
console.log(f.test2.f);
I can do something like this:
var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)
Is there a way to mutate first foo instead of creating new function?
I need it to monkey patch some dependency without recreating whole hierarchy of objects.
I need to patch a constructor function in a library, just add an alert on every call. But without juggling with prototypes
No, you can't modify the function foo refers to. You can only make foo refer to a new function that does what you want. One way to do that is to use your toString approach, but it's best to avoid that if at all possible, because the function you get as a result will not be the same as the original; the scope it has access to will be different.
Usually, you do want a proxy/wrapper, e.g.:
// The original foo
var foo = function(arg) {
return "original foo says '" + arg + "'";
};
console.log(foo("bar"));
// Let's wrap it
(function() {
var originalFoo = foo;
foo = function() {
return originalFoo.apply(this, arguments) + " plus updated foo";
};
})();
console.log(foo("bar"));
This doesn't create a hierarchy of objects or similar, it just wraps foo.
If foo is a constructor function (let's call it Foo), you'll also want to copy Foo.prototype:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());
// Let's wrap it
(function() {
var originalFoo = Foo;
Foo = function() {
var rv = originalFoo.apply(this, arguments);
this.arg += " (plus more from augmented foo)";
return rv;
};
Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());
And of course, if you need to wrap a function on Foo.prototype, you can do it just like foo in my first example:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());
// Let's wrap its getArg
(function() {
var originalGetArg = Foo.prototype.getArg;
Foo.prototype.getArg = function() {
return originalGetArg.apply(this, arguments) + " updated";
};
})();
console.log(f.getArg());
Note how it doesn't matter that we wrapped the prototype function after creating the f object.
When I implement a class to the browser's root-scope:
window.Foo = (function() {
function Foo() {}
return Foo;
})();
Is it necessary or good practice to add the root prefix every time it is referenced? E.g.
var a = new window.Foo();
or is the following fine?
var a = new Foo();
Once attached to window, you can refer it from anywhere without the window. prefix. Beware of naming clashes though:
window.Foo = (function() {
function Foo() {}
return Foo;
})();
(function someOtherFunction() {
var Foo = function() { return 'Not global!'; }
var foo = new Foo(); // Not the global one!
var globalFoo = new window.Foo(); // The global one.
})();
I want to build a function outside a jQuery scope:
(function($) {
function MyObject() {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
But function MyObject is not accessible :
ReferenceError: MyObject is not defined
However, if i build my function in the scope, it's working:
(function($) {
function MyObject() {
console.log('foo');
};
var $my_object = new MyObject();
}(jQuery));
foo
How access to MyObject outside the scope ?
I would probably not recommend it but you can basically do what you want by returning the functions as part of an object and assigning the IIFE to a variable like this
var library = (function ($) {
var exports = {};
var private = 'see you cant get this';
var MyObject = exports.MyObject = function (_in) {
console.log(_in);
};
var another_func = exports.sum = function (a, b) {
console.log(a + b);
};
return exports;
}(jQuery));
library.MyObject('foobar'); // "foobar"
library.sum(3, 5); // 8
console.log(private); // Uncaught ReferenceError: private is not defined
Although I don't know why you want to do it.. Maybe this helps
// Define Class globally
// window.MyObject also works
var MyObject = (function($) {
// Passes jQuery in
return function () {
console.log('foo');
};
}(jQuery));
var $my_object = new MyObject();
In Javascript, the way to create classes (or objects) is to use;
function MyObj()
{
this.someVar = "xyz";
this.someMethod = function(){}
}
My simple question is how different is this function from a normal JavaScript function...say a function which adds 2 numbers?
The function aren't different. What makes the difference is how you call them.
For example, those have the same effect :
function MyObj(){
this.someVar = "xyz";
this.someMethod = function(){
console.log(this.someVar);
}
}
var obj = new MyObj();
obj.someMethod();
and
function someMethod(){
console.log(this.someVar);
}
function MyObj(){
this.someVar = "xyz";
}
var obj = new MyObj();
someMethod.call(obj);
and
function someMethod(){
console.log(this.someVar);
}
function MyObj(){
this.someVar = "xyz";
}
var obj = new MyObj();
obj.f = someMethod;
obj.f();
As you tagged your question prototypal-inheritance, I'll complete by saying the best way to build your function would have been this one :
function MyObj(){
this.someVar = "xyz";
}
MyObj.prototype.someMethod = function(){
console.log(this.someVar);
}
var obj = new MyObj();
obj.someMethod();
This way, all instances of MyObj share the same function and thus are lighter.
The difference is not so much in the contents of the function, but in how you call it.
If you call var myObj = new MyObj() then a new object is created. By convention functions intended for use like this start with a capital letter.
If you were to call the function without the new keyword then exactly the same things happen inside the function, except that this will be the global object instead of the newly created object. This wouldn't matter in a simple "add 2 numbers" function, but can cause very odd bugs if you forget it.
One way to ensure that it doesn't matter if you forget the new call is to put this in the top of your function:
function MyObj() {
if (! (this instanceof MyObj)) {
return new MyObj();
}
...
}
None. What matters is the use of the new keyword.
See here:
function Fun(){
this.method = function(){
return "Bar";
}
return "Foo";
}
var value = Fun(); // assigns the return value of Fun() to value
alert(value); // "Foo"
// alert(value.method()); // won't work because "Foo".method doesn't exist
var instance = new Fun(); // assigns a new instance of Fun() to instance
alert(instance); // [object Object]
alert(instance.method()); // "Bar"