Duck typing
You can invoke an object's method on another object, as long as the latter has everything the method needs to operate properly. Example:
function foo() {
// the last element of arguments is popped
Array.prototype.forEach.pop.bind(arguments)();
// this works as if arguments had a "forEach" method
Array.prototype.forEach.bind(arguments)(function(a){ console.log(a) });
}
Dynamic scoping
The easiest way to archive dynamic scoping in JavaScript is to use
eval
:
var x = 1;
function g() {
console.log(x);
x = 2;
}
function f() {
// create a new local copy of `g` bound to the current scope
var x = 3;
eval(String(g));
g();
}
f(); // prints 3
console.log(x); // prints 1
Perhaps this is one of the few valid reasons to use
eval
in JavaScript.
Loose augmentation
Suppose that you have several module files that share a
MODULE
variable. Then
it is preferable to let organize each module file like
var MODULE = MODULE || {}; // MODULE is always declared due to hoisting
(function() {
var private_var; // only accessible to myFunction
MODULE.myFunction = ... // augment the module with a new function
})();
In this way, you can load all of your module files asynchronously without the need to block,
given that the functions defined in the module don't depend on each other.
Call-site memorization
The word memoization refers to function-level caching for repeating values.
Suppose we have a function G such that G(f) will compute an expensive function f many times.
If f is pure, then we can cache the results of f without modifying G or introducing global variables.
Instead of calling G(f) directly, we pass to G a closure of f as follows:
var memorize = function(f) {
var cache = {};
return function(x) {
if(!cache.hasOwnProperty(x))
cache[x] = f(x);
return cache[x];
};
};
G(memorize(f));
The use of cache here is totally transparent from the view of G. Note: You may want to use an LRU/LFU cache to avoid running out of memory.
No comments:
Post a Comment