关于浏览器:使用javascript缓存闭包

Caching a closure in javascript

阅读以下问题的答案后:JavaScript内部函数和性能

我想知道在这种情况下是否可以缓存内部函数(doSomethingCool):

1
2
3
4
5
function newUser(user){
         function doSomethingCool(){
                 console.log(user);
         }
}


您无法真正缓存闭包。如果这样做,它仍然会关闭最初定义的函数的变量。

例如,您可能会考虑这样做,乍一看似乎没问题:

1
2
3
4
5
6
7
8
9
10
var newUser = (function() {
    var doSomethingCool;

    function newUser(user){
         doSomethingCool = doSomethingCool || function(){console.log(user);};
         doSomethingCool();
    }

    return newUser;
}());

我们第一次调用newUser时,将创建doSomethingCool函数。这是输出:

1
2
> newUser('foo')
  foo

当我们第二次调用该函数时,闭包将被重用。这是输出:

1
2
> newUser('bar')
  foo

为什么?因为闭包仅关闭函数调用的变量,所以它是在其中定义的。

如果您真的想"缓存"该功能,则必须对其进行参数化:

1
2
3
4
5
6
7
8
9
10
var newUser = (function() {
    var doSomethingCool;

    function newUser(user){
         doSomethingCool = doSomethingCool || function(user){console.log(user);};
         doSomethingCool(user);
    }

    return newUser;
}());

但是我不会称其为闭包。从技术上讲,它是一个闭包,但是您不使用此属性。

实际上,这样写起来要容易得多:

1
2
3
4
5
6
7
8
9
var newUser = (function() {
    var doSomethingCool = function(user){...};

    function newUser(user){
         doSomethingCool(user);
    }

    return newUser;
}());


使用闭包的目的是保留创建闭包的上下文。如果"缓存"闭包,则对user的引用将始终相同,从而无法达到目的。您可能想要的是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
function User(name) {
   this.name = name;
}

User.prototype.doSomethingCool = function() {
   console.log(this.name);
}

var userA = new User('a');
var userB = new User('b');

userA.doSomethingCool();
userB.doSomethingCool();

使用该代码,仅在User原型上创建了一个doSomethingCool函数,但是其行为根据其调用方式而改变。

如果您只是想创建仅在newUser中使用但不利用闭包属性的实用程序函数,则最好移动该函数并接受用户作为参数。就是说,我非常怀疑将其保留在那里会以任何明显的方式影响您的性能。


这是一个使用基本闭包和函数的简单缓存。它的驱逐策略是一种基于概率的策略,但是您可以轻松地将其修改为基于时间的策略。与其他一些解决方案不同,该解决方案不需要您调用new并委托传入的函数。它还使用一个对象作为其cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const cache = (f, prob) =>{
    const c = {}

    return (args) => (Math.random() < prob && c.hasOwnProperty(args)
                      && c[args]) || (c[args] = f(args))
};

const doThing = (param1) = cache((param1) => {
    console.log(`called with param ${param1}`)
    return Math.random()
},.1)

console.log(doThing("christian"))
console.log(doThing("christian"))
console.log(doThing("bongiorno"))

执行1:

1
2
3
4
5
called with param christian
0.7340898868131249
0.7340898868131249
called with param bongiorno
0.3708897404988516

执行n:

1
2
3
4
5
0.6886668809537186
called with param christian
0.5845787434396792
called with param bongiorno
0.2618603367580965