In ColdFusion, if you want to reference
<cfargument name="x">
then you say:
arguments.x
In JavaScript, if you have a function:
var myFunction = function(x) {
then, is there a way to explicitly reference the arguments scope like maybe:
arguments[0].x
or something so that you're scoping everything.
There is no way to achieve the same functionality by using the arguments variable, as it holds no information on parameter names. To circumvent this, you could switch from using multiple parameters to one compound parameter object that holds actual parameter values in its members.
<script>
function abc(params) {
var x = params.x;
var y = params["y"];
}
abc( { x: 10, y: "hello" });
</script>
This way however you lose some of the readability of the code at the function signature, plus you must provide param names on the calling side.
You can reference the arguments pseudo-variable, but the arguments are indexed by number, not by name. It's a good idea to avoid messing with arguments directly; a common idiom is to convert it to a real array:
var args = Array.slice.call(arguments, 0);
I'm afraid not. You can explicitly use x or arguments[0] but nothing more. Unless, as pointed out from others, you pass an object.
Related
So I'm trying to figure out the best way to get this to work. I have a long list of code that's pulling off of a JSON database, and I'm trying to streamline it. I've created the following function:
var insertData = function(formattedData, originalData, referencePoint, insertPoint, insertStyle) {
var formattedData = originalData.replace("%data%", referencePoint);
$(insertPoint).insertStyle(formattedData);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
Is it possible to define a dot function similar to how I have it here - referenced as one of the function's variables? This current code says that insertStyle is not a function - how do I get the code to recognize that insertStyle should be taking a variable name? As in, if my fifth variable called by insertData is append, it should be read as .append.
As a reference, here's how I'm calling the function:
insertData("formattedHeaderName", "HTMLheaderName", bio.name, "#header", "prepend");
Thanks for any assistance or thoughts in advance!
You're looking for a computed property:
$(insertPoint)[insertStyle](formattedData);
Basically, every property access can be represented as a computed property:
foo["bar"]; // same as foo.bar
In your original code, you're using a non-computed property so the interpreter looks for a method literally called "insertStyle", which doesn't exist.
When you pass an argument to a function, like you do in:
insertData("formattedHeaderName", "HTMLheaderName", bio.name, "#header", "prepend");
Those arguments are strings. Not jQuery methods.
So, a solution would be to define all the methods you need to use...
And just compare the string passed to decide.
var insertData = function(formattedData, originalData, referencePoint, insertPoint, insertStyle) {
var formattedData = originalData.replace("%data%", referencePoint);
if(insertStyle=="prepend"){
$(insertPoint).prepend(formattedData);
}
if(insertStyle=="append"){
$(insertPoint).append(formattedData);
}
if(insertStyle=="after"){
$(insertPoint).after(formattedData);
}
// And so on...
}
Maybe there is some other ways to achive this...
But this one is quick and easy to implement.
I have a function:
function hello(param){ console.log('param is '+param); }
And two calls. First:
hello(123)
Second:
var a=123; hello(a);
Is there any possible way to tell, from within the hello function, whether param was passed as a var or as a literal value?
NOTICE: I am not trying to solve a problem by this. There are many workarounds of course, I merely wanted to create a nice looking logging function. And also wanted to learn the boundaries of JavaScript. I had this idea, because in JavaScript we have strange and unexpected features, like the ability to obtain function parameter names by calling: function.toString and parsing the text that is returned.
No, primitives like numbers are passed by value in Javascript. The value is copied over for the function, and has no ties to the original.
Edit: How about using an object wrapper to achieve something like this? I'm not sure what you are trying to do exactly.
You could define an array containing objects that you want to keep track of, and check if its in there:
var registry = [] // empty registry
function declareThing(thing){
var arg = { value: thing } // wrap parameter in an object
registry.push(arg) // register object
return arg; //return obj
}
function isRegistered(thingObj){
return (registry.indexOf(thingObj) > -1)
}
var a = declareThing(123);
hello(a);
function hello(param){
console.log(isRegistered(param));
}
I'm familiar with the way call(), which you can pass a variable number of arguments that will be loaded into a function's parameters when called. I'm trying to do something related where I recurse through nested set objects in RaphaelJS with forEach (analogous to jQuery's each), determine whether the child element is another set, and apply a function with a variable number of arguments if not. I want to make it generic so that I can apply any function, but make the functions that I pass have simple parameter constructors without having to access the arguments property of the function.
function recursiveFncApply(set, fnc, args) {
set.forEach(function(item) {
if (item.type == 'set') {
recurseApplyFncToSets(item, fnc, args);
} else {
fnc(item, args);
}
});
}
function translateOperation(element, operation, x, y)
// do stuff to element with operation, x, and y args without accessing
// accessing arguments property
}
recursiveFncApply(passedSet, translateOperation, [arg1, [arg2, ...]]);
I want to do this so that I can use multiple functions without having to repeat myself with code that determines arguments and properly assigns them before usage. I'm not sure whether there's some kind of functionality or language utility that I'm missing that would enable me to do this, or somehow to programmatically "construct" a function call from the remaining arguments passed to recursiveFncApply. Is this possible in JavaScript?
Clarification: I want to pass a variable number of arguments to my recursive function that will be passed to any function that I want to be applied to the contents of the sets my recursive function is working on. So I want to be able to make recursiveFncApply work generically with any function while still using an argument structure that works like a function being executed via call().
Say I have another function in addition to translateOperation:
function anotherFunction(element, differentArg) {
// do something with one argument
}
Ideally I could then use my recursiveFncApply in this way:
recursiveFncApply(passedSet, translateOperation, operation, x, y);
recursiveFncApply(passedSet, anotherFunction, singleArg);
As well as this way:
recursiveFncApply(passedSet, anotherFunction, singleArg);
I believe that this is similar to how call() works in that I could do:
anotherFunction.call(this, element, differentArg);
.. without having to change the structure of anotherFunction to sort out the arguments property, or pass an object/array.
It turns out that Felix King had the right idea/was the closest. I found a direct answer to my question as soon as I realized what I was actually trying to do, which is pass forward arguments from function to function (found the answer here). So I got this to work with this code:
function recursiveSetFncApply(set, fnc/*, variable */) {
var me = this;
var parentArgs = arguments;
set.forEach(function(element) {
if (element.type == 'set') {
parentArgs[0] = element;
me._recursiveSetFncApply.apply(me, parentArgs);
} else {
// Generate args from optional arguments and pass forward; put element in args at front
var args = Array.prototype.slice.call(parentArgs, 2);
args.unshift(element);
fnc.apply(element, args);
}
});
}
I make a reference to arguments with parentArgs because I need to update the set property in arguments before I pass it forward to the next recursive loop, otherwise I hit an infinite loop because it hasn't updated at all because it's using the original arguments set. I was under the impression that apply() will not actually pass forward arguments, but simply pop an array into the new function that you have to access by index--this isn't the case. When I used apply() on translateElementOperation, I had all the arguments I needed in their exact places. Here's the updated function I ran through the recursive apply:
function translateElementOperation(element, operation, x, y) {
var currentPath = element.attr('path');
translatedPath = Raphael.transformPath(currentPath, [operation, x, y]);
element.attr('path', translatedPath);
}
Thanks for the help, everyone!
Use .apply instead of .call
functionName.apply(element, [any, number, of, variables, ...]);
// instead of this
functionName.apply(element, set, of, variables, ...);
This is more useful like so:
var fnVars = [];// fill this anyway you want.
functionName.apply(element, fnVars);
Is it possible to find the name of an anonymous function?
e.g. trying to find a way to alert either anonyFu or findMe in this code http://jsfiddle.net/L5F5N/1/
function namedFu(){
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var anonyFu = function() {
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var findMe= function(){
namedFu();
anonyFu();
}
findMe();
This is for some internal testing, so it doesn't need to be cross-browser. In fact, I'd be happy even if I had to install a plugin.
You can identify any property of a function from inside it, programmatically, even an unnamed anonymous function, by using arguments.callee. So you can identify the function with this simple trick:
Whenever you're making a function, assign it some property that you can use to identify it later.
For example, always make a property called id:
var fubar = function() {
this.id = "fubar";
//the stuff the function normally does, here
console.log(arguments.callee.id);
}
arguments.callee is the function, itself, so any property of that function can be accessed like id above, even one you assign yourself.
Callee is officially deprecated, but still works in almost all browsers, and there are certain circumstances in which there is still no substitute. You just can't use it in "strict mode".
You can alternatively, of course, name the anonymous function, like:
var fubar = function foobar() {
//the stuff the function normally does, here
console.log(arguments.callee.name);
}
But that's less elegant, obviously, since you can't (in this case) name it fubar in both spots; I had to make the actual name foobar.
If all of your functions have comments describing them, you can even grab that, like this:
var fubar = function() {
/*
fubar is effed up beyond all recognition
this returns some value or other that is described here
*/
//the stuff the function normally does, here
console.log(arguments.callee.toString().substr(0, 128);
}
Note that you can also use argument.callee.caller to access the function that called the current function. This lets you access the name (or properties, like id or the comment in the text) of the function from outside of it.
The reason you would do this is that you want to find out what called the function in question. This is a likely reason for you to be wanting to find this info programmatically, in the first place.
So if one of the fubar() examples above called this following function:
var kludge = function() {
console.log(arguments.callee.caller.id); // return "fubar" with the first version above
console.log(arguments.callee.caller.name); // return "foobar" in the second version above
console.log(arguments.callee.caller.toString().substr(0, 128);
/* that last one would return the first 128 characters in the third example,
which would happen to include the name in the comment.
Obviously, this is to be used only in a desperate case,
as it doesn't give you a concise value you can count on using)
*/
}
Doubt it's possible the way you've got it. For starters, if you added a line
var referenceFu = anonyFu;
which of those names would you expect to be able to log? They're both just references.
However – assuming you have the ability to change the code – this is valid javascript:
var anonyFu = function notActuallyAnonymous() {
console.log(arguments.callee.name);
}
which would log "notActuallyAnonymous". So you could just add names to all the anonymous functions you're interested in checking, without breaking your code.
Not sure that's helpful, but it's all I got.
I will add that if you know in which object that function is then you can add code - to that object or generally to objects prototype - that will get a key name basing on value.
Object.prototype.getKeyByValue = function( value ) {
for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) {
if( this[ prop ] === value )
return prop;
}
}
}
And then you can use
THAT.getKeyByValue(arguments.callee.caller);
Used this approach once for debugging with performance testing involved in project where most of functions are in one object.
Didn't want to name all functions nor double names in code by any other mean, needed to calculate time of each function running - so did this plus pushing times on stack on function start and popping on end.
Why? To add very little code to each function and same for each of them to make measurements and calls list on console. It's temporary ofc.
THAT._TT = [];
THAT._TS = function () {
THAT._TT.push(performance.now());
}
THAT._TE = function () {
var tt = performance.now() - THAT._TT.pop();
var txt = THAT.getKeyByValue(arguments.callee.caller);
console.log('['+tt+'] -> '+txt);
};
THAT.some_function = function (x,y,z) {
THAT._TS();
// ... normal function job
THAT._TE();
}
THAT.some_other_function = function (a,b,c) {
THAT._TS();
// ... normal function job
THAT._TE();
}
Not very useful but maybe it will help someone with similar problem in similar circumstances.
arguments.callee it's deprecated, as MDN states:
You should avoid using arguments.callee() and just give every function
(expression) a name.
In other words:
[1,2,3].forEach(function foo() {
// you can call `foo` here for recursion
})
If what you want is to have a name for an anonymous function assigned to a variable, let's say you're debugging your code and you want to track the name of this function, then you can just name it twice, this is a common pattern:
var foo = function foo() { ... }
Except the evaling case specified in the MDN docs, I can't think of any other case where you'd want to use arguments.callee.
No. By definition, an anonymous function has no name. Yet, if you wanted to ask for function expressions: Yes, you can name them.
And no, it is not possible to get the name of a variable (which references the function) during runtime.
I have a function that would use other variables, depending on what has been passed.
Like this = ActionBar(slot) slot contains "one".
and I would like to create a call inside that like object.slot.name but it should convert it before hand to make the command look like object.one.name. Is there a way to do this in javascript/jquery?
I remember vaguely that some other language does this as {slot} or something like that.
Sorry if this question was already asked, I've checked google and stackoverflow too, but didn't find an answer.
Also I'd like to know what's the proper programming term for this kind of variable passing?
Edited it cause of misunderstandings. I'm looking into OOP js, so object is an object, one is an object, and name is an attribute, but when passing I'm passing "one" as a string to the function.
Tried eval, it doesn't work while dotted with an object.
Source code:
function disableActionButton(slot){
$("#"+slot).attr("disabled","disabled")
gcd = player.slot.gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
$("#"+slot).removeAttr("disabled").css("color","black").val(player.slot.name);
}, player.slot.gcd*1000)
}
It's really unclear what your current structure is (much clearer now you've posted code, see "update" below), but fundamentally the way to do this sort of thing in JavaScript is to have a container object. (If you don't already have one, introduce one.) Then slot can refer to a property of that object, like this:
var container = {
one: "This is one",
two: "This is two"
};
// ...
function foo(slot) {
console.log(container[slot]);
}
// ...
foo("one"); // ends up logging "This is one"
foo("two"); // ends up logging "This is two"
This works because the container object has properties, which in JavaScript can be referred to in two different ways:
Using dot notation and a literal name, e.g. container.one, or
Using bracketed notation and a name in a string, e.g. container["one"].
They're exactly equivalent except where the property name comes from. And of course, in the second case, the property name needn't be a literal string, it can be the result of any expression, including a variable reference (e.g., you can get the name from slot).
This works with all object properties, including properties that refer to functions. I mention this only because you mentioned functions in your question, so if you need to, you can do this:
function foo(slot) {
container[slot]();
}
...which calls the function on container that the property with the name held by the slot argument. So if slot is "one", it does container.one().
Update:
Your source directly echos the container example above, just apply the above to it:
function disableActionButton(slot){
$("#"+slot).attr("disabled","disabled")
// ---------v----v---- here
gcd = player[slot].gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
// ------------------------------------------------------------ and here--v----v
$("#"+slot).removeAttr("disabled").css("color","black").val(player[slot].name);
// ------v----v------- and here
}, player[slot].gcd*1000)
}
Or, rather than looking up the slot data each time, grab it once and reuse it:
function disableActionButton(slot){
// Grab it once...
var slotdata = player[slot];
$("#"+slot).attr("disabled","disabled")
// ---vvvvvvvvv--- then use it
gcd = slotdata.gcd*1000
cd = setInterval(function(){
gcd = gcd - 10
$("#"+slot).val(gcd+"ms").css("color","red");
},10)
setTimeout(function(){
window.clearInterval(cd)
$("#"+slot).removeAttr("disabled").css("color","black").val(slotdata.name);
}, slotdata.gcd*1000)
}
There's no special name for this. You're passing a property name into a function, and the function is looking up the property on the player object using that name. In some other languages this might be called "reflection" but the term doesn't really apply to dynamic languages like JavaScript.