【问题标题】:Caching a closure in javascript在javascript中缓存一个闭包
【发布时间】:2011-09-22 13:04:09
【问题描述】:

看完问题的答案:JavaScript inner-functions and Performance

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

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

【问题讨论】:

  • 我不想更改 newUSer 的签名/定义
  • 为了清楚我想缓存'doSomethingCool'

标签: javascript browser node.js closures


【解决方案1】:

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

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:

called with param christian
0.7340898868131249
0.7340898868131249
called with param bongiorno
0.3708897404988516

执行n:

0.6886668809537186
called with param christian
0.5845787434396792
called with param bongiorno
0.2618603367580965

【讨论】:

    【解决方案2】:

    你不能真正缓存一个闭包。如果你这样做了,那么它仍然会关闭它最初定义的函数的变量。

    例如,您可能会考虑这样做,乍一看可能还可以:

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

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

    > newUser('foo')
      foo
    

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

    > newUser('bar')
      foo
    

    为什么?因为闭包只关闭函数 invocation 中定义的变量。

    如果你真的想“缓存”函数,你必须参数化它:

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

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

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

    var newUser = (function() {
        var doSomethingCool = function(user){...};
    
        function newUser(user){
             doSomethingCool(user);
        }
    
        return newUser;
    }());
    

    【讨论】:

    • 我不想改变newUser函数定义,newUser的内部impl可以是任何...
    • @browsingLoops:我认为函数的定义就是它的实现。
    【解决方案3】:

    使用闭包的目的是保留创建它的上下文。如果您“缓存”您的闭包,则对 user 的引用将始终相同,从而违背了目的。你可能想要的是这样的:

    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 中使用但不利用闭包属性的实用函数,您最好移动该函数并接受用户作为参数。也就是说,我非常怀疑将其留在那里会以任何明显的方式影响您的表现。

    【讨论】:

      猜你喜欢
      • 2014-03-25
      • 1970-01-01
      • 2019-11-11
      • 2017-04-17
      • 2018-09-30
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多