Open zhu-ting opened 6 years ago
Significant chunks explain just how the nature of functions as first-class objects can be exploited to our great benefit. But first, let’s take a look at some of the actions we can take with objects. In JavaScript, objects enjoy certain capabilities:
var ninja = {};
ninjaArray.push({});
ninja.data = {};
function hide(ninja){
ninja.visibility = false;
}
hide({});
function returnNewNinja() {
return {};
}
var ninja = {};
ninja.name = "Hanzo";
It turns out that, unlike in many other programming languages, in JavaScript we can do almost the exact same things with functions also.
Functions in JavaScript possess all the capabilities of objects and are thus treated like any other object in the language. We say that functions are first-class objects, which can also be:
function ninjaFunction() {}
var ninjaFunction = function() {};
ninjaArray.push(function(){});
ninja.data = function(){};
function call(ninjaFunction){
ninjaFunction();
}
call(function(){});
function returnNewNinjaFunction() {
return function(){};
}
They can possess properties that can be dynamically created and assigned:
var ninjaFunction = function(){};
ninjaFunction.name = "Hanzo";
Whatever we can do with objects, we can do with functions as well. Functions are objects, just with an additional, special capability of being invokable: Functions can be called or invoked in order to perform an action. One of the characteristics of first-class objects is that they can be passed to functions as arguments. In the case of functions, this means that we pass a function as an argument to another function that might, at a later point in application execution, call the passed-in function. This is an example of a more general concept known as a callback function. Let’s explore this important concept.
Whenever we set up a function to be called at a later time, whether by the browser in the event-handling phase or by other code, we’re setting up a callback. The term stems from the fact that we’re establishing a function that other code will later “call back” at an appropriate point of execution.
var text = "Domo arigato!";
console.log("Before defining functions");
function useless(ninjaCallback) {
console.log("In useless function");
return ninjaCallback();
}
function getText() {
console.log("In getText function");
return text;
}
console.log("Before making all the calls");
alert(useless(getText) === text,
"The useless function works! " + text);
console.log("After the calls have been made");
Before defining functions Before making all the calls In useless function In getText function
Alert('true') After the calls have been made
var text = 'Domo arigato!';
function useless(ninjaCallback) {
return ninjaCallback();
}
console.log(useless(function () { return text;}) === text, "The useless function works! " + text);
VM544:5 true "The useless function works! Domo arigato!"
Now let’s consider a use of callbacks that will greatly simplify how we sort collections.
All JavaScript arrays have access to the sort method that requires us only to define a comparison algorithm that tells the sort algorithm how the values should be ordered. This is where callbacks jump in! Instead of letting the sort algorithm decide what values go before other values, we’ll provide a function that performs the comparison. We’ll give the sort algorithm access to this function as a callback, and the algorithm will call the callback whenever it needs to make a comparison. The callback is expected to return a positive number if the order of the passed values should be reversed, a negative number if not, and zero if the values are equal; subtracting the compared values produces the desired return value to sort the array:
var values = [0, 3, 2, 5, 7, 4, 8, 1];
values.sort(function(value1, value2){
return value1 - value2;
});
The functional approach allows us to create a function as a standalone entity, just as we can any other object type, and to pass it as an argument to a method, just like any other object type, which can accept it as a parameter, just like any other object type. It’s that first-class status coming into play.
In this section, we’ll examine ways to exploit the similarities that functions share with other object types. One capability that might be surprising is that there’s nothing stopping us from attaching properties to functions:
// Creates an object and assigns a new property to it
var ninja = {};
ninja.name = "hitsuke";
// Creates a function and assigns a new property to it
var wieldSword = function(){};
wieldSword.swordType = "katana";
Let’s look at a couple of the more interesting things that can be done with this capability:
var store = {
nextId: 1,
cache: {},
add: function(fn) {
if (!fn.id) {
fn.id = this.nextId++;
this.cache[fn.id] = fn;
return true;
} }
};
function ninja(){}
assert(store.add(ninja),
"Function was safely added.");
assert(!store.add(ninja),
"But it was only added once.");
JavaScript provides a couple of ways to define functions, which can be divided into four groups:
function myFun(){ return 1;}
myArg => myArg*2
new Function('a', 'b', 'return a + b')
function* myGen(){ yield 1; }
Besides the position in code where they’re placed, there’s one more difference between function declarations and function expressions: For function declarations, the function name is mandatory, whereas for function expressions it’s completely optional.
Parentheses around function expressions One more thing might be nagging you about the way we’ve immediately called our func- tion expression: the parentheses around the function expression itself. Why do we even need those? The reason is purely syntactical. The JavaScript parser has to be able to easily differentiate between function declarations and function expressions. If we leave out the parentheses around the function expression, and put our immediate call as a separate statement function(){}(3), the JavaScript parser will start pro- cessing it, and will conclude, because it’s a separate statement starting with the key- word function, that it’s dealing with a function declaration. Because every function declaration has to have a name (and here we didn’t specify one), an error will be thrown. To avoid this, we place the function expression within parentheses, signaling to the JavaScript parser that it’s dealing with an expression, and not a statement.
Immediate function is an important concept in JavaScript development because it allows us to mimic modules in JavaScript. We’ll focus on this application of IIFEs in chapter 11.
+function(){}();
-function(){}();
!function(){}();
~function(){}();
When it comes down to brass tacks【实质问题】, the main difference between writing JavaScript code like the average and writing it like a JavaScript ninja is understanding JavaScript as a functional language. The level of sophistication of all the code you’ll ever write in JavaScript hinges on this realization.