introduce
Some of the modes we introduced in this article are called initialization mode and performance mode, which are mainly used for initialization and performance improvement. Some modes have been mentioned before, so here is just a summary.
Functions that are executed immediately
In the 4th chapter of this series, "Function Expressions Called Now", we have described similar functions in detail. Here we will just give two simple examples to summarize.
The code copy is as follows:
// After declaring the function, execute the function immediately
(function () {
console.log('watch out!');
} ());
// Functions declared in this way can also be executed immediately
!function () {
console.log('watch out!');
} ();
// The following method is also OK
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
Immediately executed object initialization
This pattern means that when an object is declared (not a function), one of the methods in the object will be executed immediately to perform initialization work. Usually, this pattern can be used in code executed at one time.
The code copy is as follows:
({
// Here you can define constants and set other values
maxwidth: 600,
maxheight: 400,
// Of course, you can also define utility methods
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// Initialization
init: function () {
console.log(this.gimmeMax());
// More code...
}
}).init(); // This starts initialization
Branch initialization
Branch initialization refers to the initialization of different codes according to different conditions (scenarios), which is the so-called conditional statement assignment. Before, when we were doing event processing, we usually used codes like the following:
The code copy is as follows:
var utils = {
addListener: function (el, type, fn) {
if (typeof window.addEventListener === 'function') {
el.addEventListener(type, fn, false);
} else if (typeof document.attachEvent !== 'undefined') {
el.attachEvent('on' + type, fn);
} else {
el['on' + type] = fn;
}
},
removeListener: function (el, type, fn) {
}
};
Let's improve it. First, we need to define two interfaces, one for add event handle and the other for remove event handle. The code is as follows:
The code copy is as follows:
var utils = {
addListener: null,
removeListener: null
};
The implementation code is as follows:
The code copy is as follows:
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else if (typeof document.attachEvent !== 'undefined') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else { // Other old browsers
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}
Isn't it very convenient to use? The code is much more elegant.
Self-declaring functions
Generally, the function code of the same name is rewrite inside the function, such as:
The code copy is as follows:
var scareMe = function () {
alert("Boo!");
scarMe = function () {
alert("Double boo!");
};
};
This kind of code is very confusing. Let's first look at the execution results of the example:
The code copy is as follows:
// 1. Add new attributes
scarMe.property = "properly";
// 2. scareMe assigns a new value
var prank = scarMe;
// 3. Call as a method
var spooky = {
boo: scarMe
};
// Call with new variable name
prank(); // "Boo!"
prank(); // "Boo!"
console.log(prank.property); // "properly"
// Call using the method
spooky.boo(); // "Boo!"
spooky.boo(); // "Boo!"
console.log(spooky.boo.property); // "properly"
Through the execution result, it can be found that assigning the function to a new variable (or internal method), the code does not execute the overloaded scarMe code, and the following example is exactly the opposite:
The code copy is as follows:
// Use self-declaring functions
scarMe(); // Double boo!
scarMe(); // Double boo!
console.log(scareMe.property); // undefined
When using this model, you must be very careful, otherwise the actual result may be different from the result you expect. Of course, you can also use this special to do some special operations.
Memory optimization
This pattern mainly uses the attribute characteristics of the function to avoid a large number of repeated calculations. The usual code form is as follows:
The code copy is as follows:
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... Complex operation...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache storage
myFunc.cache = {};
However, there is a problem with the above code. If the passed parameter is toString or some common methods similar to Object, the problem will occur. At this time, you need to use the legendary hasOwnProperty method, the code is as follows:
The code copy is as follows:
var myFunc = function (param) {
if (!myFunc.cache.hasOwnProperty(param)) {
var result = {};
// ... Complex operation...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache storage
myFunc.cache = {};
Or if you pass in multiple parameters, you can use JSON's stringify method to produce a cachekey value for storage. The code is as follows:
The code copy is as follows:
var myFunc = function () {
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
result;
if (!myFunc.cache[cachekey]) {
result = {};
// ... Complex operation...
myFunc.cache[cachekey] = result;
}
return myFunc.cache[cachekey];
};
// cache storage
myFunc.cache = {};
Or multiple parameters, you can also use the arguments.callee feature:
The code copy is as follows:
var myFunc = function (param) {
var f = arguments.callee,
result;
if (!f.cache[param]) {
result = {};
// ... Complex operation...
f.cache[param] = result;
}
return f.cache[param];
};
// cache storage
myFunc.cache = {};
Summarize
No need to summarize, just look at the code carefully