Coming from C, every function needs a name that is used to call that specific function. but in the JavaScript code below, there is no name at all.
Well in JavaScript, that's just not the case – functions can indeed be anonymous (nameless) functions. Sometimes you'll hear them called "lambdas" or redundantly called "lambda functions".
But more importantly, functions are first class data members in JavaScript, meaning:
They can be assigned to variables
let y = x => x + 5
y(3)
// 8
They can be passed as arguments to other functions
let xs = [1,2,3]
let y = x => 2 * x
xs.map(y)
// [2,4,6]
They can be returned from a function
let add = x => {
return y => x + y
}
let f = add(1)
f(2)
// 3
They can be included in data structures
let pikachu = {
number: 25,
shock: enemy => enemy.damage(30),
growl: enemy => enemy.sadden(40)
}
pikachu.growl(meowth)
// "It's very effective!"
So what's the take away here? Well, in JavaScript, you need to think of functions as being no different than any other value (eg) 1, "foo", or [{user: 'bob'}, {user: 'alice'}] – conceptually, they are just data and they're all first class
How to understand your code
Here's your code affectionally reformatted by me. Since you originally asked about ES6, I'm going to substitute your lambdas with ES6 arrow functions
let something = []
let object = { a: true, b: true, c: true }
for (let key in object) {
something.push(() => console.log(key))
}
something.forEach(func => func())
// a
// b
// c
Using high level descriptors, the nature of this code is
- iterate thru each key of
object, add some value to something
- iterate thru each value of
something, do something with that value
In your case, some value is a function, but I want to show you what your code would look like if we used another kind of value
let something = []
let object = { a: true, b: true, c: true }
for (let key in object) {
// this time push a string, instead of an anonymous function
something.push("the key is: " + key)
}
something.forEach(str => console.log(str))
// the key is: a
// the key is: b
// the key is: c
So now we can see how the code works when a different value type (String) is used. Aside from using a string, the only other thing we did was change
// from
func => func()
// to
str => console.log(str)
The reasoning here is
in your original code, something is an array of functions, so for each of those functions, func, we call func()
in the modified code, something is an array of strings, so for each of those strings, str, we call console.log(str)
Dissection of Array.prototype.forEach
The last remaining bit to understand is the super-powered forEach function. Remember point number 2 in the first class capabilities: first class data members can be passed as arguments to other functions.
forEach expects its argument to be a function. So forEach is a function that accepts another function. This kind of function is called a higher-order function.
Don't let these fancy names distract you from their underlying simplicity. Making our own higher-order functions like forEach is actually really easy. Always just remember that functions are like any other value – below, we'll write our own version of forEach so you can see how it works
let something = []
let object = { a: true, b: true, c: true }
// forEach accepts an array and some function, f
let forEach = (arr, f) => {
// iterate thru each value of arr
for (let value of arr) {
// call f on each value
f(value)
}
}
for (let key in object) {
something.push("the key is: " + key)
}
forEach(something, str => console.log(str))
// the key is: a
// the key is: b
// the key is: c
So now we see the string array working with our own forEach function. Let's make sure it works with your original lambda array, too.
let something = []
let object = { a: true, b: true, c: true }
let forEach = (arr, f) => {
for (let value of arr) {
f(value)
}
}
for (let key in object) {
something.push(() => console.log(key))
}
forEach(something, func => { func() })
// a
// b
// c
Remarks
And that's it! Functions aren't special snowflakes in JavaScript. They're just like all the datums.
Coming from a C perspective, it might take awhile to think about functions in this way. But really, you should leave everything you understand about any language at the door when you're walking into the home of any new programming language. Each language has its own way of expressing itself yielding a unique set of strengths and weaknesses. By bringing in a "strength" of some language A to another language B, you might be substituting one of B's own strengths for one of it's weaknesses.
JavaScript is a multi-paradigm language making it rather suitable for imperative, object-oriented, and functional programming styles. Because of its jack-of-all-trades nature, it's probably not the best oop or fp language, but it's still rather impressive that it can express a particular solution to a problem in a wide variety of ways.
object's keys to the console. The second just executes every function in the array.