官术网_书友最值得收藏!

Immediate invocation

There's yet another common usage of functions, usually seen in popular libraries and frameworks, that lets you bring into JS (even the older versions!) some modularity advantages from other languages. The usual way of writing this is something like the following:

(function() {
// do something...
})();

Another equivalent style is (function(){ ... }()) -- note the different placement of the parentheses for the function call. Both styles have their fans; pick whichever suits you, but just follow it consistently.

You can also have the same style, but passing some arguments to the function, which will be used as the initial values for its parameters:

(function(a, b) {
// do something, using the
// received arguments for a and b...
})(some, values);

Finally, you could also return something from the function:

let x = (function(a, b) {
// ...return an object or function
})(some, values);

The pattern itself is called, as we mentioned, Immediately Invoked Function Expression -- usually simplified to IIFE, pronounced iffy. The name is easy to understand: you are defining a function and calling it right away, so it gets executed on the spot. Why would you do this, instead of simply writing the code inline? The reason has to do with scopes.

Note the parentheses around the function. This helps the parser understand that we are writing an expression. If you were to omit the first set of parentheses, JS would think you were writing a function declaration instead of an invocation.  The parentheses also serve as a visual note, so readers of your code will immediately recognize the IIFE. 

If you define any variables or functions within the IIFE, because of JS's function scope, those definitions will be internal, and no other part of your code will be able to access it. Imagine you wanted to write some complicated initialization, like the following:

function ready() { ... }
function set() { ... }
function go() { ... }
// initialize things calling ready(),
// set() and go() appropriately

What could go wrong? The problem hinges on the fact that you could (by accident) have some function with the same name of any of the three here, and hoisting would imply that the latter function would be called:

function ready() {
console.log("ready");
}
function set() {
console.log("set");
}
function go() {
console.log("go");
}
ready();
set();
go();

function set() {
console.log("UNEXPECTED...");
}
// "ready"
// "UNEXPECTED"
// "go"

Oops! If you had used an IIFE, the problem wouldn't have happened. Also, the three inner functions wouldn't even be visible for the rest of the code, which helps keeping the global namescape less polluted:

(function() {
function ready() {
console.log("ready");
}
function set() {
console.log("set");
}
function go() {
console.log("go");
}
ready();
set();
go();
})();

function set() {
console.log("UNEXPECTED...");
}
// "ready"
// "set"
// "go"

To see an example involving returned values, we could revisit the example from Chapter 1, Becoming Functional - Several Questions, and write the following, which would create a single counter:

const myCounter = (function() {
let count = 0;
return function() {
count++;
return count;
};
})();

Then, every call myCounter() would return an incremented count -- but there is no chance that any other part of your code will overwrite the inner count variable because it's only accessible within the returned function. 

主站蜘蛛池模板: 宁远县| 灌云县| 贡觉县| 奈曼旗| 仁怀市| 修武县| 怀化市| 商都县| 彭泽县| 彰化县| 新巴尔虎左旗| 墨竹工卡县| 昌黎县| 淮南市| 巍山| 双流县| 安平县| 班戈县| 淅川县| 枣阳市| 定南县| 四平市| 巴青县| 桐庐县| 凤山市| 重庆市| 泰来县| 西林县| 新郑市| 旬邑县| 富蕴县| 小金县| 嘉义县| 泸水县| 韶关市| 明水县| 宁陵县| 定南县| 和静县| 交口县| 阜宁县|