The only reason you are able to call Function.prototype.snapshotFunction
as Function.snapshotFunction
is because Function
is itself a function, as are Object
, String
, Number
, and any other JavaScript "class". If you replaced Function
with String
, this would no longer work. You added a method to all functions and called it on the function instance Function
. So if you tried using this
, it would reference the built-in Function
function. So yes, this should either be a free-standing function, or, if you wanted to make it a method (e.g. getPrimitive.snapshot(["testPrimitive", testPrimitive])
), then remove the first parameter of the function, and replace all references to it in the function with this
. Speaking of this
, I can't think of all the use cases for your function involving this
, but with code like this, it's pretty likely this
will cause something to break. I found an example here.
IMO, the [string, value, string, value, ...] thing is bad API design, and doesn't match the intended semantics of an array/list/collection (then again, neither does using them as tuples, but I'm pretty sure I've seen that before, sigh...). Some alternatives: preferably [{name:theName, value:theValue}, ...]
, but you can also do (because your keys are strings) [{theName:theValue}, ...]
, or even [[theName, theValue], [theName2, theValue2], ...]
(so succumbing to using arrays as tuples) would be better. This is more of an opinion, but I'm sure I'm not alone in thinking this.
Also, out of curiosity, did you want the animals' sounds
property to be able to contain objects as well as arrays? Because, you know for(var k in obj)
iterates through obj
's keys (viewing it as an object), rather than what C#'s foreach does, right?
If you wanted to iterate over an arbitrary object's keys, then you can do what Scott suggested, although I prefer a more inline approach:
for(var s in animal.sounds) {
(function(sound) {
myAnimal["say" + animal.sounds[sound]] = function() {
console.log(animal.sounds[sound]);
}
})(s);
}
Another way to write it (what I would've done at first, although it's basically exactly the same as the above as far as I can see, the above might be better practice though, not sure about this myself):
for(var s in animal.sounds) {
(function() {
var sound = s;
myAnimal["say" + animal.sounds[sound]] = function() {
console.log(animal.sounds[sound]);
}
})();
}
In this case, you could've even done:
for(var s in animal.sounds) {
(function(soundVal) {
myAnimal["say" + soundVal] = function() {
console.log(soundVal);
}
})(animal.sounds[s]);
}
If you wanted to iterate over an array, then it's easier:
// since forEach takes a function, which creates a new scope, you don't have to do it in addition to for's code block (which does not create a new scope in JS)
animal.sounds.forEach(function(soundVal) {
myAnimal["say" + soundVal] = function() {
console.log(soundVal);
}
});
You can also use forEach
with an object and its keys using Object.keys(obj)
(it's a bit different than what for...in iterates through though).
So that takes care of the iteration example. In the demo code you gave with your function, you can do the same thing (in JS parameters are pass reference by value, and same with closures as far as I know, so object mutation is externally visible, while variable reassignment is not, which makes your last example work also).
Scott: Thanks for the clarification - my understanding was that a callback just referred to a wrapper around a specific function, regardless of what parameters it took: it's good to figure out the technical definition.