Function in a variable, passing a parameter - javascript

I can't seem to get back on track with this one. I simply put a function in a variable and want to call it later, providing it with a parameter:
var logic = function(itemId) {
console.log(itemId);
};
jQuery("#flipright").click(function() { logic.apply(1); } );
This prints "undefinded".
What am I missing?

Simply call logic(1).
If you want to pass a context, you can use call or apply :
logic.apply(context, [1]);
// or
logic.call(context, 1);
You should use apply or call if you want to pass a context to another function - meaning that the this keyword in the called function will refer to whatever context you are passing to it.
Here's a scenario :
var logic = function(itemId) {
console.log(this,itemId);
};
jQuery("#flipright").click(function() {
// output to console the current jquery object and "1"
logic.call(this,1);
});

Make it:
jQuery("#flipright").click(function() { logic(1); } );
ref for apply: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

Related

Bind Mocking Function inside function

I am writing QUnit test case for my application . Basically I have three Files
like below . DataServices.js has getObjectDetails method which does ajax call
to get data and passes result in callback .
Resolver.js loads DataServices.js using require.
I am writing test case for Proxy.resolve method , in which i want to avoid actual api call , to do this I created mock object of DataServices in Test.js and call Resolver proxy resolve method .
I tried using bind , But still points to actual method of DataServices.js not what I bind in Test.js
DataServices.js
define(["module"], function(module) {
"use strict";
var Details = {
getObjectDetails :function(param,callback){
//API AJAX CALL
// Callback once done
}
};
return {Details : Details }
});
Resolver.js
define(["DataServices"],function(DataServices){
var Proxy= {
resolve : function(){
var Details = DataServices.Details ;
Details.getObjectDetails("xyz", function(result){
// Do Operation After Result
});
}
};
return {Proxy:Proxy}
});
Test.js
define(["Resolver.js" ],function(Resolver){
var DataServices= {
Details : {
getObjectDetails : function(undefined,onSuccess, onError) {
return onSuccess({"X":"Y"});
}
}
};
Resolver.Proxy.resolve.bind(DataServices);
Resolver.Proxy.resolve(); // This is still calling DataServices.js Details
// Not the above muck object
});
In simple program , I want to call mock z function , not z which is inside x .
How to achieve this.
var x = {
z:function(b){
console.log("Z Actual Function..."+b);
},
a : function(){
this.z(3);
}
};
var z = function(b){
console.log("Mock ..."+b)
}
x.a.bind(z);
x.a();
//Z Actual Function...3
But I want Mock ...3 to print
First problem
Using .bind creates a new function, it doesn't change the value of this in the original function.
To use bind in your case you would do something like this instead:
var mockedA = x.a.bind(z);
mockedA();
If you want to call the function immediately without assigning it to a variable you can use .call or .apply instead.
eg:
x.a.call(z); // runs `a()` immediately with `this` set to `z`
The second problem
By binding x.a to z you're changing the value of this to the value provided (the mock z function). So inside x.a when you call this.z(3) you're effectively trying to call z.z(3), which is a non existent function and so will throw a TypeError.
There are probably better ways of doing it but this is a way that answers your question:
var x = {
z:function(b){
console.log("Z Actual Function..."+b);
},
a : function(){
this.z(3);
}
};
var mock = {};
mock.z = function(b){
console.log("Mock ..."+b)
}
// with bind
var mockXA = x.a.bind(mock);
mockXA();
// with call
//x.a.call(mock)

GoJS: use more than one parameter in a conversion function

I need to use two properties of a node in GoJS to perform a particular operation. Here is my current code:
$(go.Picture,
{
//some properties
},
new go.Binding("source", "item_status", getIcon)),
//....
function getIcon(item_status) {
//do something
}
Is it possible to modify the above code so that getIcon() function gets a second parameter called item_id? E.g can i do something like this:
new go.Binding("source", "item_status","item_id", getIcon)),
....
function getIcon(item_status, item_id) {}
Thanks
Answering my own question again...
to get all data for a particular node, you can pass "" instead of "item_status" to the Binding function.
go.Binding("source", "", getIcon)),
...
getIcon(node){
var x = node.item_status;
var y = node.key;
}

how to add an argument to a method stored in an array that is called later

This is a follow-up to this question (although this is self-contained) trying to `call` three methods but not working correctly with jQuery map.
I am trying to store a set of methods in an array but there is a set that might have arguments like below (the initial methods are in before_methods and the proposed methods are in lm_methods). I'm sure it's pretty self explanatory what I want but I'd like to be able to merge in the arguments into a reasonable call to f (specifically the arc.pLikedByTerm). I currently have the following:
// signature
pLikedByTerm:function(term, ne, sw, m){
....
}
// code before_methods just to show
this.before_methods=[arc.pLocations,arc.pLikedLocations,arc.pLikedItems];
this.lm_methods=[arc.pLocations,arc.pLikedLocations,arc.pLikedItems, arc.pLikedByTerm('surfing'),arc.pLikedByTerm('sailing')];
$.each(this.lm_methods, function(i,f){
f(ne,sw,m);
});
How would I do this or is this bad design? What would be the idiomatic way? My brain is fried.
thx in advance
Update 1
Playing around with answer below, it looks like this works which might the simplest things:
var fns=[logStuff("this is msg"), logMoreArgs("a term","a you msg")];
for (var i=0; i<fns.length; i++) {
fns[i];
}
Having an array of functions is common practice when used often. For example, consider this Callback class.
function Callback(){
this.callbacks = [];
}
Callback.prototype.run = function(cb) {
for (var i=0; i<this.callbacks.length; i++) {
this.callbacks[i]();
}
};
We can then add some callbacks.
function logStuff(msg) {
jsprint(msg || "No message");
}
obj = new Callback();
obj.callbacks.push(logStuff);
obj.callbacks.push(logStuff);
obj.run();
If we run this we see that it's only logging our default value. So if we want to bind some data, we can use the bind function.
Function.prototype.bind
thisArg
The value to be passed as the this parameter to the target
function when the bound function is called. The value is ignored if
the bound function is constructed using the new operator.
arg1, arg2, ...
Arguments to prepend to arguments provided to the bound function
when invoking the target function.
Our new code sets the first parameter to different strings, which we then see. You can bind any number of parameters.
obj = new Callback();
obj.callbacks.push(logStuff.bind(null, "My message"));
obj.callbacks.push(logStuff.bind(null, "My other message"));
obj.run();
end result
The way you are doing would work just ok. Just remove the arguments and parens:
Instead of:
this.lm_methods=[arc.pLocations,arc.pLikedLocations,arc.pLikedItems,
arc.pLikedByTerm('surfing'),arc.pLikedByTerm('sailing')];
Do:
this.lm_methods=[arc.pLocations,arc.pLikedLocations,arc.pLikedItems,
arc.pLikedByTerm,arc.pLikedByTerm];
Example:
function say(txt) {
console.log("say" + txt);
}
function shout(txt) {
console.log("shout" + txt);
}
function whisper(txt) {
console.log("whisper" + txt);
}
var funcArr = [say, shout, whisper];
$.each(funcArr, function(i, f) {
f("hello");
});
would print:
sayhello
shouthello
whisperhello

Javascript Function Calls: Regular call vs Call vs Bind Call

My question is simple:
I'm passing a function to some other function to be call later (sample callback function), the question is when, why and what is the best practice to do it.
Sample:
I have the xxx() function, and I have to pass it, as I show you below in the window.onload event.
What is the best practice and why? There is any performance aspect or why should I choose to use call or bind to call this function
function xxx(text)
{
var div = document.createElement("div");
div.innerHTML = text + " - this: " + this.toString();
document.body.appendChild(div)
}
function callFunction(func)
{
func("callFunction");
}
function callUsingCall(func)
{
func.call(this, ["callUsingCall"]);
}
function callUsingBind(func)
{
func.call(this, ["callUsingCall"]);
}
window.onload = function(){
callFunction(xxx);
callUsingCall(xxx);
callUsingBind(xxx.bind(document));
}
Thank you,
Sebastian P.
I don't think there's any "best" practise.
You use call if the function you're calling cares what this is.
You use bind if you want to ensure that the function can only be called with the specified value of this.
[There's some overhead to both, i.e. at least one depth of function calls / scope]
Otherwise you just call the function.
Simples :)
The this object is the context of the function. It's like you make a machine that something for you, and the this object would be the place that the machine works in, like your house. You can move it as you like.
We have 4 ways setting this objects.
Calling the function that is not a method:
fn(someArguments)
This way the this object is set to null or probably the window object.
Calling the function as a method:
someObject.fn(someArguments)
In this case the this object will point to someObject and it's mutable.
Calling with call or apply methods of the function.
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])
In this case the this object will point to someObject here. You are forcing it to have another context, when calling it.
Binding a the function
var fn2 = fn.bind(anotherObject, someArguments)
This will create another function that is binded to that this object we gave it(anotherObject). No matter how you call it, the this object is going to be the same.
Use Cases
Now you can do some tricky stuff knowing this. The reason that why we have it here(I think it came first from C++) is that methods of an object need to access to their parent. The this object provides the access.
var coolObject = {
points : ['People are amazing'],
addPoint : function (p) { this.points.push(p) }
}
So if you do the following it won't work:
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');
The error will be thrown because the this object is not our coolObject anymore and doesn't have the points property. So at times like this, you can something like this:
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');
This is pointless, but the function will work, even the this object is not what its supposed to be.
var anotherCoolObject = {
points : ['Im a thief!'],
addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');
Still the function will work if you call it like that, since the this object will point to anotherCoolObject which has the points property.
The most popular use case I've seen is slicing the arguments object:
function returnHalf() {
return [].slice.call(arguments, 0, arguments.length / 2);
}
returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']
So you see, arguments object is not an instanceof array. If we do arguments.slice(...) then you're gonna be killed by the compiler. But here we use the array's method on arguments object, since it's array like.
Sometimes you don't want your function context to be changed or you wanna add your own arguments, you use bind.
For example when you add a listener for an event with jquery, when jquery calls your function, the this object will be the element. But sometimes you wanna do tricky stuff and change it:
var myElement = {
init : function () {
$(this.element).click(this.listener.bind(this));
},
view : "<li>${Name}</li>",
name : 'ed',
element : $('#myelement'),
listener : function () {
this.element.append($.tmpl( this.view, this ));
}
}
myElement.init();
So here, you bind it to the myElement, so you can have access to the object properties to render the view. Another examples would be the following:
for (var i = 0; i < 10; i++) {
setTimeout(function () {console.log(i)}, 10)
}
// All of them will be 10.
for (var i = 0; i < 10; i++) {
setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}
If you have put an asynchronous function call in a loop, by the time the callback is called, the loop is finished, and the counter have reached the end, you can use bind to cleanly bind the current counter to your callback.
Another good use case of it, that I use a lot is when passing my functions with arguments to async module, without creating closures.
async.parallel({
writeFile : function (cb) {
fs.writeFile('lolz.txt', someData, cb);
},
writeFile2 : function (cb) {
fs.writeFile('lolz2.txt', someData, cb);
}
}, function (err){
console.log('finished')
});
async.parallel({
writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){
console.log('finished')
});
These two implementations are identical.
Performance
Just check these out:
http://jsperf.com/bind-vs-call2
http://jsperf.com/js-bind-vs-closure/2
http://jsperf.com/call-vs-closure-to-pass-scope/10
bind has a big performance overhead comparing to other types of calling, but make sure you don't sacrifice performance with maintainability with pre-mature optimizations.
Also you can have a look at this article.

Can you use a function argument directly in a namespace?

I have the following function:
prevPage: function (store){
myapp.stores.store.proxy.extraParams = { sendpage: myapp.stores.store.data.items[0].data.currentPage -1 };
},
Which basically modifies the extraParams namespace according to whatever 'store' is entered as an argument in the function, but it doesn't work. I think I am using 'store' wrong in the function definition.
To rephrase, if I define the function as:
prevPage: function (){
myapp.stores.examplestore.proxy.extraParams = { sendpage: myapp.stores.store.data.items[0].data.currentPage -1 };
},
It works correctly for the examplestore namespace.
How do I do it so I can have that namespace as a variabl argument in the function?
You have to write it this way myapp.stores[store].proxy.extraParams where store is a string.

Categories

Resources