I've got a JS object that looks like so:
return {
foo: function() {
return this.bar();
},
bar: function() {
return 1;
}
}
Why do I keep getting a TypeError: this.bar is not a function logged in FireBug? What's the proper way to reference the bar() method from foo() in the same object?
Update
So I've posted a fiddle with the whole code here. The return call is actually part of a RequireJS define. Let me know if any further clarification is required.
It depends on how it is called; If for instance theObject.foo is passed as callback to another function (e.g. jQuery(x).on("click", theObject.foo)), the this context will probably be lost.
A way to enforce that bar calls foo is to make a closure. Change the function that returns the object as:
function thatReturnsTheOject() {
var ret = {
foo: function() {
return ret.bar(); // <---- Using `ret` not `this`
},
bar: function() {
return 1;
}
};
return ret;
}
Another way, more complex but may result in a more familiar language usage is this:
function thatReturnsTheOject() {
var ret = {};
ret.foo = (function() {
return this.bar(); // <---- Using `this` again
}).bind(ret); // <---- but note the `bind()`
ret.bar = function() {
return 1;
};
return ret;
}
Related
I am trying to override a toString() method, but getting into difficulties.
Already looked here and here, but still no luck.
My code is as follows:
var Foo = function(arg) {
// some code here...
return function (a, b, c) {
// return function code...
};
};
Foo.prototype.toString = function () {
return "string representation of function";
};
exports.bar(arg) {
return Foo(arg);
};
In another module:
var mod = require('the-module-from-above');
console.log(mod.bar().toString()); // prints return function source code.
My question is, how come my toString() function isn't called, and how can I make it get called?
thank you.
You only set things on a function's prototype if you're using the function as a constructor with new. Since you don't appear to be doing that here, you need to set the toString function on the actual function you return.
function fooToString() {
return "string representation of function";
}
var Foo = function(arg) {
// some code here...
var ret = function (a, b, c) {
// return function code...
};
ret.toString = fooToString;
return ret;
};
You could also add the toString function when you actually create the object in the bar function, if you'd prefer to do that.
exports.bar(arg) {
var foo = Foo(arg);
foo.toString = fooToString;
return foo;
};
Is there a way to do:
foo() // return string "foo"
foo.bar() // return string "bar"
?
I tried to experiment with functions and objects. But nothing happened.
function foo() {
return "foo";
}
foo.bar = function() {
return "bar";
};
Or, if you prefer:
var foo = function() {
return "foo";
};
foo.bar = function() {
return "bar";
}
JS functions are a type of object so you can assign properties/methods to them the same as for any other object.
You can call either a function or a class named foo but you can't have both as far as I know. Correct me if I'm wrong. Why would you want a class and a function with the same way anyway? I'm assuming that that's what you want as there is little info in your post
To define a function use this
function foo() {
console.log("foo");
}
And call it like in your example.
To define a class do it like this (here are some other ways to do it).
var foo = {
bar: function() {
console.log("bar");
}
}
And again, call it like you did in your example.
While learning Javascript, I tried to re-declare the apply property of a function. Thus far no problem.
function foo() { return 1; }
alert(foo()); // 1
alert(foo.apply(null)); // 1
foo.apply = function () { return 2; }
alert(foo()); // 1
alert(foo.apply(null)); // 2
Now, I tried to make apply do something more and call the "old" apply (like logging).
var old = foo.apply;
foo.apply = function() {
alert("A");
return old(null);
}
alert(foo.apply(null));
I get
TypeError: Function.prototype.apply was called on [object Window],
which is a object and not a function
I tried
foo.apply = function() {
alert("A");
return arguments.callee[Function.prototype.apply](null);
}
alert(foo.apply(null));
I get
TypeError: Property 'function apply() { [native code] }' of object function () { alert("A"); return arguments.calleeFunction.prototype.apply; } is not a function
Is there any real way to accomplice what I try? Or is it some restriction due to Function.prototype.apply being native code?
Yes. apply expects to be applyed (yes, with exactly itself) on a function, while the way you used it (by old()) makes its this value the global object (window). So you can do this:
var old = foo.apply; // === Function.prototype.apply
foo.apply = function() {
// "this" is the function foo
alert("A");
return old.apply(this, arguments); // applying the (old) apply function on foo
// or better without any arguments:
return old.call(this); // like this(); which is foo()
}
alert(foo.apply(null));
// and the call solution with an argument:
foo.apply = function(context) {
return old.call(this, context);
// like this.call(context);
// which is foo.call(context)
// which is like context.foo()
}
Also check out the docs for the call and apply "methods" (though we've use old not as a method, but as a pure function).
why doesn't this work as expected. (see expected comment)
var Module = function () {
var public_instance_var;
function doStuff () {
Module.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
}
}();
Module.doStuff();
Update: Fixed accordingly to a few of jAndy suggestions
Multiple errors here:
You don't return DoStuff as module interface
instance_var is not declared, probably meant public_instance_var
doOtherStuff is never assigned to Module, just call it like doOtherStuff();
Fixed code:
var Module = function () {
var public_instance_var;
function doStuff() {
doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
doStuff: doStuff,
public_instance_var: public_instance_var
}
}();
Module.doStuff();
change your code like so
var Module = function () {
var public_instance_var;
function doStuff () {
doOtherStuff();
console.log("var is ", public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff : doStuff
}
}();
Module.doStuff();
you have to return doStuff() function (otherwise outside it will be undefined) and public_instance_var instead of instance_var
you need to execute doOtherStuff() without prefixing Module.
What this code does is, simply put: create and run a function and assign its return value to a variable: Module. The return value is an object with 1 property: public_instance_var, that points to the variable instance_var, or (after correcting the typo: public_instance_var). This variable was declared, but not instantiated. Therefore the return value looks like this:
Module.public_instance_var = undefined
The very last line Module.doStuff(); won't work one bit: Module is an object that has no methods. The functions you declared are garbage collected when the anonymous function returns. If you want access to those functions, you'll need to include them in the return statement. Read up on closures, Object constructors and design patterns in general, but I'd say the code you're after will look something like this:
var Module = (function()
var public_instance_var;
function doStuff () {
this.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
};
})();
Of course, this way your variable public_instance_var is a public property, so my guess would be what you're really trying to do is simulate a private properties and methods. In which case you might end up with code similar to this:
var Module = (function()
{
var public_instance_var;
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
this.doOtherStuff();//this, you're referencing the object's property
console.log('here I am');
},
doOtherStuff: function ()
{
public_instance_var = true;
//this won't work anymore:
//this.public_instance_var = true;
};
}
})();
Module.doStuff() now logs here I am, but the doOtherStuff is now a public method, too. Here's how you might choose to solve the issue:
var Module = (function()
{
var public_instance_var;
function doOtherStuff ()
{
public_instance_var = true;
};
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
doOtherStuff();//don't use this here, but the reference to the function exists thanks to closure
console.log('here I am');
console.log(public_instance_var);//logs true
}
};
})();
These are just a few of the very powerful things you can do with closures and functions returning objects. Just read a couple of articles, like this one, there are better ones out there. Google the term power constructors
var obj = {
func: function() {
return: {
add: function() {
}
}
},
somefunc: function() {
}
}
The orginal code behind where i used to convert this...
var hash = (function() {
var keys = {};
return {
contains: function(key) {
return keys[key] === true;
},
add: function(key) {
if (keys[key] !== true){
keys[key] = true;
}
};
})();
Questions:
What is the use of return keyword?
Can i structure like this, my class?
On the most basic level, the return keyword defines what a function should return. So if I have this function:
function foo() { return 4; }
And then call it:
var bar = foo();
foo() will return 4, hence now the value of bar is also 4.
Onto your specific example:
In this use case the return is used to basically limit outside access to variables inside the hash variable.
Any function written like so:
(function() {...})();
Is self-invoking, which means it runs immediately. By setting the value of hash to a self-invoking function, it means that code gets run as soon as it can.
That function then returns the following:
return {
contains: function(key) {
return keys[key] === true;
},
add: function(key) {
if (keys[key] !== true){
keys[key] = true;
}
}
};
This means we have access to both the contains and add function like so:
hash.contains(key);
hash.add(key);
Inside hash, there is also a variable keys but this is not returned by the self-invoking function that hash is set to, hence we cannot access key outside of hash, so this wouldn't work:
hash.keys //would give undefined
It's essentially a way of structuring code that can be used to create private variables through the use of JavaScript closures. Have a look at this post for more information: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-private-variables-in-javascript/
Hope this Helps :)
Jack.
An anonymous function that is executed immediately is commonly used to create a scope. Any variables that you declare inside the scope is local to the function, so they don't pollute the global scope.
The return statement is used to return an object from the anonymous function:
var hash = (function() {
return { ... };
})();
You could write the same using a named function:
function createHashObject() {
return { ... };
}
var hash = createHashObject();
I don't know what is your actual code is but these are the closures john
function addGenerator( num ) {
return function( toAdd ) {
return num + toAdd
};
}
var addFive = addGenerator( 5 );
alert( addFive( 4 ) == 9 );
in this you can see use of return