Check this fiddle or the code below:
function abc(s) {
console.log('in abc(s)');
}
function abc(s, t) {
console.log('in abc(s,t)');
}
abc('1');
The output of this question is always in abc(s,t)
Can someone please explain me whats going on here and why ?
In Javascript there is no overload concept.
You can however write a function that checks how many arguments have been passed by using the arguments value.
function foo(s, t) {
if (arguments.length == 2) {
...
} else {
...
}
}
all arguments that the function expects in the signature but that are not passed by the caller are received as undefined. You can also write variadic functions by simply accessing the n-th argument passed with arguments[i]. Note however that arguments is not a Javascript array, so not all array methods are available for it.
About being able to redefine the same function multiple times without errors things are a bit complex to explain because the rules are strange.
A simple explanation is you could think of is that function is an executable statement like it is in Python and so the last function definition wins. This would be wrong however because, differently from Python, the following is legal Javascript code:
console.log(square(12));
function square(x) { return x*x; }
i.e. you can call a function in lines that are preceding the definition (in a script: of course typing those two lines in a Javascript console wouldn't work).
A slightly more correct explanation is that the compiler first parses all the function definitions (last wins) and then starts executing the code. This mental model works if you don't put functions inside if because what happens in practice in that case is implementation dependent (and I'm not talking about crazy IE, but even that FF and Chrome will do different things). Just don't do that.
You can even use the form
var square = function(x) { return x*x; }
and in this case it's a simple assignment of a "function expression" to a variable that is executed when the flow passed through it (so it's ok to place different implementations of a function inside different if branches, but you cannot call the function before assigning it an implementation).
First, no method overload support in JavaScript (see #6502 workaround).
Second, to describe what you're experiencing, in JavaScript, the last declared function (with the same name) is invoked because the former has been overwritten, It relates to JavaScript Hoisting.
Try to reorder the functions declarations and see the output result again:
function abc(s, t) {
console.log('in abc(s,t)');
}
function abc(s) {
console.log('in abc(s)');
}
abc('1');
In javascript, there is only one function with any given name and if multiple functions with the same name are declared, the last one declared will be the one that is active.
You can however test the arguments that are passed to your function and implement many of the same types of behaviors that function overloading is designed to handle. In fact, in some cases you can do even more.
In your specific example:
function abc(s, t) {
// test to see if the t argument was passed
if (t !== undefined) {
console.log('was called as abc(s,t)');
} else {
console.log('was called as abc(s)');
}
}
abc('1'); // outputs 'was called as abc(s)'
abc('1', '2'); // outputs 'was called as abc(s,t)'
But, you can also get much, much more creative (and useful).
For example, the jQuery .css() method can be called five different ways.
.css( propertyName )
.css( propertyNames )
.css( propertyName, value )
.css( propertyName, function(index, value) )
.css( properties )
The code inside the .css() method examines the type and number of the arguments to figure out which way it is being called and therefore exactly what operation to carry out.
Let's look at how this could be done to figure out which of the 5 forms of this function are being used:
css: function(prop, value) {
// first figure out if we only have one argument
if (value === undefined) {
if (typeof prop === "string") {
// we have a simple request for a single css property by string name
// of this form: .css( propertyName )
} else if (Array.isArray(prop)) {
// we have a request for an array of properties
// of this form: .css( propertyNames )
} else if (typeof prop === "object") {
// property-value pairs of css to set
// of this form: .css( properties )
}
} else {
if (typeof value === "function") {
// of this form: .css( propertyName, function(index, value) )
} else {
// of this form: .css( propertyName, value )
}
}
}
You can also implement optional arguments. For example, jQuery's .hide() can accept many forms. One of the forms is .hide( [duration ] [, complete ] ) where both the duration and the completion function are optional. You can pass nothing, just a duration or both a duration and completion callback function. That could be implemented like this:
hide: function(duration, fn) {
// default the duration to zero if not present
duration = duration || 0;
// default the completion function to a dummy function if not present
fn = fn || function() {};
// now the code can proceed knowing that there are valid arguments for both
// duration and fn whether they were originally passed or not
}
I find one of the most useful ways of using these variable arguments are to allow code to support a variety of different argument types so that no matter what state your arguments are in, you can just pass them as you have them without having to convert them to some universal type. For example, in this implementation of a set object in javascript, the .add() method can take all of these different forms of arguments:
s.add(key)
s.add(key1, key2, key3)
s.add([key1, key2, key3])
s.add(key1, [key8, key9], key2, [key4, key5])
s.add(otherSet) // any other set object
s.add(arrayLikeObject) // such as an HTMLCollection or nodeList
This both accepts a variable number of arguments and it accepts a number of different types for each argument and it will adapt based on what is passed to it. So, you can initialize a set via a list of keys, an array of keys, from another set, from a pseudo array or any mixture of those types. Internally, the code just iterates through each argument that was passed to the function, checks the type of the argument and acts accordingly.
You can see the code here on GitHub for further info on how this is done.
Related
I don't know if you've ever felt like you've dived off the stupid tree and hit every branch on the way down, but JavaScript has that effect on me, an experienced PHP programmer but just doesn't get JS sometimes.
so I wrote this function using jQuery.extend({ .. }) as follows:
loadSection: function(obj){
if(typeof obj=='undefined')obj=event.target; //but this doesn't work
if(typeof obj=='string')obj=document.getElementById(obj);
var params=null;
var instr={};
var k=0;
while(true){
..etc..
I want to be able to call it two ways:
$.loadSection($('#employee-data-173'));
//or $loadSection('employee-data-173') for convenience
or:
$('#employee-data-173').loadSection();
Clearly (to you anyway!) I'm not grasping the concept of what's being passed in the second case. And that's not even getting into a case like this:
$('.someElement').click(loadSection);
You want to use the same function in three totally different usecases. In each case different arguments are automatically passed to the function. So first declare and prepare it to handle all possible types of arguments:
function loadSection(index, obj, args) {
var element, params = null;
if (obj && obj.nodeType) { // for usecase 2
element = obj; if (typeof args == 'object') params = args;
} else {
if (typeof obj == 'object') params = obj;
if (typeof index == 'string') { // usecase 1 with selector-string
element = document.getElementById(index);
else if (index.jquery) { // usecase 1 with jQuery object
if (index.length == 1) element = index[0]; // if only one element inside jQuery
// if more than one element there call this function recursively on each
else index.each(loadSection);
}
else if (index.target) element = index.target; // for usecase 3
}
/* your stuff */
}
In your usecase 1 you have to add the function to the global jQuery object and call it by $.loadSection(argument), where argument may be a id-selector-string or an jQuery-object $("selector"). There are two ways with identic result:
$.loadSection = loadSection;
$.extend({loadSection: loadSection});
In usecase 2 you want to call the function as a method of a jQuery object. Therefore you have to add it to the jQuery.prototype like so:
$.fn.loadSection = function( args ) { // $.fn is synonym for jQuery.prototype
return this.each(loadSection, args);
};
If you call now $("selector").loadSection() the function is executed once for each element matched by "selector". Arguments index and obj are automatically passed to loadSection.
In usecase 3 the function is used as callback-function for an event. Since its prepared for this case, the event object is automatically passed to it. So just do:
$('.someElement').click(loadSection);
You can use all cases mixed in the same piece of code.
EDIT "What shall/can the function return?"
It may return whatever you want to. Only the behaviour depends on usecase.
In usecase 1 you can do: var result = $.loadSection("selector") and result gets the returned value.
In usecase 2 there is an iteration over all elements in the jQuery object. The return value of loadSection is simply ignored except you explicitely return false. Then iteration stops. So if you do if (index == 2) return false; the function is executed maximum 3 times even when you have 7 elements inside jQuery object.
The function as a whole always returns the jQuery object, so you can do chaining:
$("selector").loadSection().css({color: 'blue'}).animate(...). ...
In usecase 3 the function is only executed but the return value gets never recognized anywhere, so you can't catch it.
EDIT 2 "How to pass additional params to the function?"
1) Now loadSection is prepared to take additional args (see above). 2) The setup of $.fn.loadSection is modified to take args (see above). 3) args must be an object or array eg {prop: 'color', id: 23} (otherwise it's ignored) but may be omitted.
In usecase 1 pass args as second argument
var result = $.loadSection("selector", args); // you find args inside in ""var params"
In usecase 2 args is the one and only possible argument. jQuery now makes an iteration inside an iteration: the function is called on each element once for each item in args!
The inner iteration is stoppable by return false, but the iteration over all elements no longer.
$("selector").loadSection({prop: 'color', id: 23}) // if $() contains 3 elems, function run six times
In usecase 3 its impossible to pass args since you only point to the function by its name.
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.
In Javascript I can call any method with more than the necessary amount of parameters and the extra parameters are silently ignored.
e.g.
letters = ['a','b','c']
//correct
letters.indexOf('a')
//This also works without error or warning
letters.indexOf('a', "blah", "ignore me", 38)
Are there ways to detect cases where this occurs?
My motivation is that in my experience cases where this occurs are usually bugs. Identification of these by code analysis or at runtime would help track these errors down.
These cases are especially prevalent where people are expecting alterations to base types which may not have occurred. Logging a warning where this happens
e.g.
Date.parse('02--12--2012', 'dd--MM--YYYY')
Notes:
To be clear I would like a solution that doesn't involve me sprinkling checks all over my code and other peoples' code.
You can use the arguments object.
function myFunction(param1,param2)
{
if (arguments.length!=2)
{
// wrong param number!
}
...
}
As per your edit: If you want to implement an automated form of check, without ever touching the original functions:
You still have to process each function with:
functionName = debug(functionName, numberOfExpectedArgs);
This operation wraps the function with a check of the number of arguments.
So we leave a sample function untouched:
// this is the original function... we want to implement argument number
// checking without insertint ANY debug code and ANY modification
function myFunction(a,b,c)
{
return a + " " + b + " " + c;
}
// the only addition is to do this...
myFunction = debug(myFunction,3); // <- implement arg number check on myFunction for 3 args
// let's test it...
console.log(myFunction(1,2,3));
console.log(myFunction(1,2));
You need to implement this debug() function:
function debug(f, n)
{
var f2 = f;
var fn = function()
{
if (arguments.length!=n) console.log("WARNING, wrong argument number");
return f2.apply(f2, arguments);
};
return fn;
}
This solution is TOTALLY transparent as per already defined functions, so it may be what you seek for.
I strongly suggest to check against deprecations (there are some) and crossbrowser compatibility.
The functions in JavaScript are objects. As such they have properties. What you want can be achieved with length MDN property, which specifies the number of arguments expected by the function.
function say ( hello, world ) {
alert (
"arguments length = " + arguments.length + "\n" +
"defined with = " + say.length
);
}
say ( "this ", "brave ", "new ", "world" );
This works even on IE8. Demo. In your case you can do something like this.
Javascript is a very dynamic language and many of its useful features also make it impossible to do some checks statically.
The existance of the arguments implicit object means there is no way to automatically determine how many arguments a function is expecting for all functions. Many var-arg functions declare no formal arguments and uses the arguments object exclusively.
All you can reliably do is to check it manually in each function like Cranio suggested.
If you want to have automated checks, e.g. as part of your unit tests, you can make use of the length property of the Function objects, which returns the number of formal arguments. For var-arg functions, just don't include the check. For example:
function checkNumberOfArguments(args) {
if (args.length != args.callee.length) {
throw new Error('Wrong number of arguments');
}
};
// Use it like
function a(b) {
checkNumberOfArguments(arguments);
}
a(1);
a(1,2);
Inside function you can use arguments object, it contains an array of all the arguments that were supplied to the function when it was called.
function x(){
return arguments.length;
}
x()
=> 0
x(1,1,1,1,1,1,1,1,1)
=> 9
Because jQuery is a widely used and mature collaborative effort, I can't help but to look at its source for guidance in writing better Javascript. I use the jQuery library all the time along with my PHP applications, but when I look under the hood of this rather sophisticated library I realize just how much I still don't understand about Javascript. Lo, I have a few questions for the SO community. First of all, consider the following code...
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
Now, is this to say that the attr() method was designed to accept EITHER an attribute name, an attribute name and a value, or a pair-value map? Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
Moving on, the whole library is wrapped in this business...
(function(window, undefined) { /* jQuery */ })(window);
I get that the wrapped parentheses cause a behavior similar to body onLoad="function();", but what is this practice called and is it any different than using the onLoad event handler? Also, I can't make heads or tails of the (window) bit there at the end. What exactly is happening with the window object here?
Am I wrong in the assessment that objects are no different than functions in Javascript? Please correct me if I'm wrong on this but $() is the all encompassing jQuery object, but it looks just like a method. Here's another quick question with a code example...
$('#element').attr('alt', 'Adopt a Phantom Cougar from Your Local ASPCA');
... Should look something like this on the inside (maybe I'm wrong about this)...
function $(var element = null) {
if (element != null) {
function attr(var attribute = null, var value = null) {
/* stuff that does things */
}
}
}
Is this the standing procedure for defining objects and their child methods and properties in Javascript? Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
I apologize for this being a bit lengthy, but answers to these questions will reveal a great deal to me about jQuery and Javascript in general. Thanks!
1. Method overloading
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
var attr = function (key, value) {
// is first argument an object / map ?
if (typeof key === "object") {
// for each key value pair
for (var k in key) {
// recursively call it.
attr(k, key[k]);
}
} else {
// do magic with key and value
}
}
2. Closures
(function(window, undefined) { /* jQuery */ })(window);
Is not used as an onload handler. It's simply creating new scope inside a function.
This means that var foo is a local variable rather then a global one. It's also creating a real undefined variable to use since Parameters that are not specified passes in undefined
This gaurds againts window.undefined = true which is valid / allowed.
the (window) bit there at the end. What exactly is happening with the window object here?
It's micro optimising window access by making it local. Local variable access is about 0.01% faster then global variable access
Am I wrong in the assessment that objects are no different than functions in Javascript?
Yes and no. All functions are objects. $() just returns a new jQuery object because internally it calls return new jQuery.fn.init();
3. Your snippet
function $(var element = null) {
Javascript does not support default parameter values or optional parameters. Standard practice to emulate this is as follows
function f(o) {
o != null || (o = "default");
}
Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
You can access properties on an object using foo.property or foo["property"] a property can be any type including functions / methods.
4. Miscellanous Questions hidden in your question
Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
An array is created using var a = [] it simply contains a list of key value pairs where all the keys are positive numbers. It also has all the Array methods. Arrays are also objects.
A map is just an object. An object is simply a bag of key value pairs. You assign some data under a key on the object. This data can be of any type.
For attr, if you give an object instead of a key value pair it will loop on each property.
Look for attr: in jQuery's code, then you'll see it use access. Then look for access: and you will see there is a check on the type of key if it is an object, start a loop.
The wrapping in a function, is to prevent all the code inside to be accessed from outside, and cause unwanted problems. The only parameters that are passed are window that allow to set globals and access the DOM. The undefined I guess it is to make the check on this special value quicker.
I read sometimes jQuery but I didn't start with it, may be you should get some good books to make you an idea first of what some advanced features Javascript has, and then apply your knowledge to the specifics of jQuery.
1 - Yes attr can accept a attribute name for getting a value, a name and a value for setting one value or a map of attribute names and values for settings more than one attribute
2 - A map is basically a JavaScript object e.g:
var map = {
'key1' : 'value1',
'key2' : 'value2'
};
3 - (function(window, undefined) { /* jQuery */ })(window); is something called an anonymous function as it doesn't have a name. In this case it also executes straight away.
A simple example would be:
function test(){
...
}
test();
//As an anonymous function it would be:
(function(){
...
}();
//And it you wanted to pass variables:
function test(abc){
...
}
test(abc);
//As an anonymous function it would be:
(function(abc){
...
}(abc);
this would make it different to the load event, as it is a function not an event.
4 - window is passed as a variable, as it is used internally within jQuery
5 - Objects and functions the same, as everything in JavaScript is an object. jQuery does something like this:
var obj = {
"init" : function(){
}
}
6 - Yes you can use . to retrieve a value on an object but you can also use [] e.g:
var map = {
"test" : 1
}
map.test //1
map["test"] //1
I hope this answers your many questions, let me know if I've missed anything out.
jQuery 1.6.1
The test is typeof key === "object"
if that is true, then you passed a { .... }
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.attr );
},
// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
access: function( elems, key, value, exec, fn, pass ) {
var length = elems.length;
// Setting many attributes
if ( typeof key === "object" ) {
for ( var k in key ) {
jQuery.access( elems, k, key[k], exec, fn, value );
}
return elems;
}
// Setting one attribute
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
return elems;
}
// Getting an attribute
return length ? fn( elems[0], key ) : undefined;
},