The important thing to note here is that, since Javascript is a dynamic language, every object is, essentially, just a glorified hash-map (with a few exceptions). And everything in a Javascript object can be accessed in two ways - bracket notation and dot notation.
I will quickly go over the two notations answering the first part of your question, and then I'll get to the second part.
Bracket notation
This mode is more similar to accessing hashmaps and arrays in other programming languages. You can access any component (data (including other objects) or function) using this syntax.
This is exactly what your are doing in your example. You have 'a'
, which is a string (and not a character literal, like it would be in a language such as C++).
Using the bracket notation, you access its toUpperCase
method. But accessing it is still not enough; simply typing alert
, for instance, in Javascript, doesn't call the method. It's just a simple statement. In order to call the function, you need to add the parenthesis: alert()
shows a simple dialog box containing undefined
, as it received no parameters. We can now use this knowledge to decipher your code, which becomes:
alert('a'.toUpperCase());
Which is much more readable.
Actually, a good way to understand this a little bit better is to execute the following Javascript:
alert(alert)
This calls alert
by passing it a function object, also alert
, without also executing the second alert. What is shown (in Chrome 26, at least) is the following:
function alert() { [native code] }
Calling:
alert(alert())
shows two consecutive message boxes containing undefined
. This is easy to explain: the inner alert()
gets executed first, shows undefined
(because it didn't have any parameters) and returns nothing. The outer alert receives the return value of inner alert - which is nothing, and also shows undefined
in a message box.
Try out all the cases on jsFiddle!
Dot notation
This is the more standard approach, which allows members of an object to be accessed using the dot (.
) operator. This is what your code would look like in dot notation:
alert('a'.toUpperCase())
Much more readable. So when should we use dot notation, and when should we use bracket notation?
Comparison
The main difference between the two methods is semantic. There are also some other details, but I'll get to those in a second. What's most important is what you actually want to do - a rule of thumb is that you use dot notation for well-established fields and methods an object has, and the bracket-notation for when you're actually using your object as a hash map.
A great example of why this rule is so important can be shown in your example - since the code is using bracket notation in a place where dot notation would have been much more sensible, it makes the code harder to read. And that's a bad thing, because code is read many more times than it is written.
In some cases, you have to use bracket notation even if using dot notation were more sensible:
if a member of an object has a name containing one or more spaces or any other special characters, you can't use dot notation: foo.some method()
doesn't work, but foo["some method"]()
does;
if you need to dynamically access an object's members, you're also stuck using bracket notation;
Example:
for(var i = 0; i < 10; ++i) {
foo["method" + i]();
}
The bottom line is that you should use bracket syntax when using the object as a hash map (foods["burger"].eat()
) and the dot syntax when working with "actual" fields and methods (enemy.kill()
). With Javascript being a dynamic language, the line between "actual" fields and methods of an object and "other" data stored within can get pretty blurry. But as long as you don't mix them in confusing ways, you should be fine.
Now, onto the rest of your question (finally! :P).
how can I be sure method will always be a member of obj
You can't. Try it. Try to call derp
on a string. You will get an error in the lines of:
Uncaught TypeError: Object a has no method 'derp'
It is kinda generic function to call ANY methods on ANY object. But
does that mean the specified method will already be an implicit member
of the specified object?
Yes, in your case it would have to be. Otherwise you end up with the error I mentioned above. However, you don't have to use return obj[method]();
in the callMethod()
function. You can add your own functionality that then gets used by the map function. Here's a hard-coded method that turns all the letters into an uppercase letter:
function makeCap()
{
return function(obj) {
return obj.toUpperCase();
}
}
var caps2 = map(['a', 'b', 'c'], makeCap()); // ['A','B','C']
console.log(caps2)
The code in the tutorial you linked to uses partial functions. They're a tricky concept by themselves. Reading more about that subject should help make things clearer than I could ever make them.
Note: this is the code of the map function used by the code in the question, source here.
function map(arr, iterator) {
var narr = [];
for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
return narr;
}