as expected it invokes the function foo the first time, but when i want to use the function another time the following error is thrown:
Uncaught TypeError: Property 'foo' of object [object DOMWindow] is not a function
the intention was to define a function (which has to be called immediately, but also later on) - do i have to write the following instead:
function foo() {...}
foo();
... // later on
foo();
or is there a more elegant solution?
EDIT: if you cannot use a variable (even if it's an anonymous function) as a function, what is its advantage anyway?
(why does
var foo = (function(){...})();
... // later on
foo();
not work?)
If you expand
var foo = (function(){...})();
foo();
you will get this:
function temp() {
...
}
foo = temp();
As you can see, you are calling the temp function (bolded here): var foo = (function(){...})();. This means that foo is not being assigned to a function object, but the return value of that function call. Therefore, unless the temporary function returns a function (and in that case you might want to consider refactoring), the value stored in foo will not be callable.
In JavaScript, there are two ways to store a function object:
A) Pass a function without calling it (i.e. foo = bar; instead of foo = bar()).
B) (If you need to pass parameters) pass a function call wrapped in another function (without calling the wrapper function) (i.e. foo = function {bar(param1, param2);}; instead of foo = function {bar(param1, param2);}(); (notice the () at the end? -- you don't want that)).
It does not work because you assign the result of calling the anonymous function to foo, instead of the function itself.
When you then try to call foo(), you are trying to treat the result of the first function call (apparently of type DOMWindow) as a function, which is incorrect.
You could use
var foo;
(foo = function(){...})();
but this is not well-readable.
Shouldn't it be
var foo = function() { ..... }
instead of
var foo = (function() { .. } ) ();
in your case you are assigning a anonymous function to foo.
Related
For example:
(function foo() {
var a = 3;
console.log(a);
});
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
obj.a(); // 2
foo(); // ReferenceError: Not Defined
How is that I can access a function expression within obj, but not in the global object?
Edits: for cohesion and clarity
You're confusing a couple of different things here.
Your first statement is a function expression, not a function declaration:
(function foo() {
var a = 3;
console.log(a);
});
This happens to be a named function expression ("foo"), but it does not introduce a variable foo in this scope. If you wanted to introduce foo so that it can be called again, you need either a function declaration...
function foo() {
var a = 3;
console.log(a);
}
foo();
or, you need to assign the function expression to a variable:
var foo = function () {
var a = 3;
console.log(a);
}
foo();
Your next bit of code, the object declaration, effectively does this by assigning the function expression to a variable, obj.a:
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
The error in your thinking here is due to confusion around foo. In both cases, foo is the name of the function, but it's not actually relevant to invoking the function. You should drop the foo because it's only confusing things.
In essence, your first snippet is equivalent to:
(function () { alert('x'); });
This line of code defines an anonymous function, but does nothing with it. The function exists briefly, is never invoked, and then is lost, because it is not assigned to anything.
Your second snippet is equivalent to:
var x = function () { alert('y') };
This code defines a variable, x, and assigns a function to it. The function can then be invoked with x(), and the function remains available as long as x is in scope.
Your original question is:
How can an object access function expression?
Which doesn't really make sense. The object can't "access the function expression", it just contains a property to which a function has been assigned, while the snippet outside the object did not retain the function in a way that would allow you to invoke it.
I have a java script as below
foo(){
return "hello";
}
var myVar=foo;
What will get assigned to myVar?
if you initialize it with function keyword:
function foo() {
return "hello";
}
then it is possible as in JavaScript in function is a Data Type so you initialized a variable named foo and then assign another variable.
var myVar = foo;
Calling now myVar() will call function as it has reference to that function now.
Here is Demo
SyntaxError Error.
I think what you want is this? In this case foo is an alias for this funciton defined
var foo = function(){
return "hello";
}
I have target object
function Foo() {
this.someVar = 'some var';
};
Foo.prototype.callback() {
console.log(this);
};
And object, that will call this callback
function Bar(callback) {
this.callback = callback;
};
Bar.prototype.onSomeAction = function() {
this.callback();
};
And initial code
foo = new Foo();
bar = new Bar();
bar.callback = foo.callback;
bar.onSomeAction();
Result: i have logged to console Bar()'s context instead of Foo().
How can i get context of Foo() in the Foo() callback?
PS: I tried closures
Foo.prototype.callback() {
var foo = this;
return function(foo) {
console.log(foo);
};
};
but it does nothing. I have not fully understanding of the closures :(
The reason your original code didn't work is that the value of this inside of a method call is the value of the object it's being called on. That means when you say:
bar.callback = foo.callback;
And then you call:
bar.callback();
The code defined here:
Foo.prototype.callback = function () {
console.log(this);
};
gets called with this being a reference to bar because bar is to the left of the . on the method call. So whenever you assign a function as an object property, calling it on that object will call it with the object as this.
You could also have written:
function callback() {
console.log(this);
}
bar.callback = callback;
bar.callback();
And you would find that this still references bar.
In fact, if you call the plain function callback(); as defined above, you'll find that this is a reference to the global object, usually window in web browsers. That's because all global variables and functions are properties of window, so callback(); is implicitly window.callback();
The fact that the value of this depends on what object is calling a function can be a problem when passing callbacks around, since sometimes you want this to reference the original object the function was a property of. The bind method was design to solve this problem, and Yuri Sulyma gave the right answer:
bar.callback = foo.callback.bind(foo);
However, the way you would do this using closures is to capture an instance of Foo within an anonymous function that calls the correct method on the correct object:
foo = new Foo();
bar = new Bar();
bar.callback = function () {
foo.callback();
};
bar.onSomeAction();
Which is essentially what bind does. In fact, we call write our own naive version of bind using a closure:
Function.prototype.bind = function (obj) {
var fn = this;
return function () {
fn.call(obj);
};
};
call let's you call a function with the value of this explicitly defined. This allows you to "set the context" the function is called in so that it's the same as calling obj.fn() when you call bar.callback(). Since when we call foo.callback.bind(foo);, obj is foo and fn is foo.callback, the result is that calling bar.callback() becomes the same as calling foo.callback().
That's where Dalorzo's answer comes from. He uses call to explicitly set the context.
There's also another function for setting the context called apply that also takes an array representing the arguments for the function as its second argument. This allows us to write a more complete version of bind by taking advantage of the special arguments variable:
Function.prototype.bind = function (obj) {
var fn = this;
return function () {
fn.apply(obj, arguments);
};
};
bar.callback = foo.callback.bind(foo);
You can polyfill Function.prototype.bind() if necessary: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
Try using these changes:
Use call to set context:
bar.onSomeAction.call(foo);
And I think your callback function needs to change to:
Foo.prototype.callback=function() {
console.log(this);
};
Let's say I have a JavaScript object, foo, that has a property, "bar", whose value is a function.
var foo = {"bar" : someFunction};
I could replace "someFunction" with an anonymous function. However, what if I wanted to define the function separately:
function someFunction() {
...
}
I can't write foo.bar = someFunction() since it will store the result of evaluating the function.
How can I set foo.bar's value to a function? How would I call it once it's set?
How can I set foo.bar's value to a function?
Without the parentheses:
foo.bar = someFunction;
How would I call it once it's set?
Treat the property as you would any function:
foo.bar();
You should simply assign the bar to some someFunction pointer, like this:
var foo = {};
function someFunction() {
};
foo.bar = someFunction;
foo.bar();
Take out the () and you should be able to set it equal to a function
foo.bar = someFunction; //assign
foo.bar(); // call
http://jsfiddle.net/sN9cs/1/
The first example is exactly how you do it. Just don't call the function:
foo.bar = someFunction;
How does JavaScript deal with functions with names ending with ()? Consider for example the following piece of code:
var foo() = function () { }; // The empty function
var bar = function(foo) { var myVariable = foo(); };
It seems like there are two possible interpretations for what foo(); means:
Execute the argument foo. This assigns myVariable the returned value of foo.
Consider foo() as the name of the function defined at first. This assigns myVariable the empty function.
Is this even legal code? If so, what are the rules?
Is this even legal code?
No:
var foo() = function () { };
should be:
var foo = function () { };
If so, what are the rules?
In this case the foo argument will have precedence because it is defined in an inner scope than the foo function. So it's really a matter of scope: where is the variable defined. The interpreter first starts by looking in the innermost scope of the code, then in the outer, ... until it reaches the global scope (the window object).
So for example the result of the following code will be 123 as seen in this live demo:
var foo = function () { alert('we are in the foo function'); };
var bar = function(foo) { var myVariable = foo(); alert(myVariable); };
bar(function() { return 123; });
The () isn't considered part of the name. You'll probably get a syntax error. You can find some naming rules here.
In javascript, brackets mean execute. So your code will fail as it will be looking for a function foo on the first line.
Identifiers may not contain any parentheses, so the first statement is illegal. The second, however, is fine, myVariable = foo() executes the foo parameter and assigns the return value.
Do you really mean "Can I pass functions as references?" If so, then the answer is yes:
var foo = function() { return 2; }
var bar = function(fn){ return fn(); }
var two = bar(foo);