Vandervals
Vandervals

Reputation: 6054

Must memoized functions be defined as variables?

I've just asked this question (multiple errors while momoizing function inside another function) and I've got a nice answer... but! Just to understand a little more about JavaScript, I'd like to know if the momoized function can be written in this style:

function main () {
    function memoized_f(){
        //memoizing code
    }
}

EDIT: Please notice I'm not asking what is the difference in the code above, I'm asking if it is possible to memoize the second one!

So, how to rewrite this?

function main() {
  var create_node = (function() {
    var memo;
    console.log("memo: " + memo);
    console.log("create_node")

    function f() {
      var value;
      if (memo) {
        value = memo.cloneNode();
        console.log("clone node");
        console.log(value);
      } else {
        var value = document.createElement("div");
        value.innerHTML = "hello";
        console.log("new node");
        console.log("value: " + value);
        memo = value;
      }
      return value;
    }
    return f;
  })();
  var collection = [];
  for (var i = 0; i < 10; i++) {
    collection.push(create_node());
  };
  // Display results
  for (var i = 0; i < 10; i++) {
    console.log(i + ". " + collection[i]);
  }
}
main();

Upvotes: 1

Views: 354

Answers (2)

apsillers
apsillers

Reputation: 115950

Your actual memoized function is f. The (function(){ ... })() IIFE wrapping merely provides a an additional closure-layer to hide the variable memo so that it is visible only to f.

To repeat that: the (function(){...})() expression is not your memoized function. It is wrapping that restricts visibility of an inner variable and ultimately returns your memoized function f, which is defined inside of it. If you were okay with exposing memo to other code in main and not restrict its visibility to the memoized function only, you could eliminate the IIFE wrapping entirely and simply rename f to create_node:

function main() {
    var memo;

    function create_node() {
      var value;
      if (memo) { value = memo.cloneNode(); }
      else {
        var value = document.createElement("div");
        value.innerHTML = "hello";
        memo = value;
      }
      return value;
    }

  // use `create_node` as originally done
  // NOTE that other code can manipulate `memo` now, though!
}
main();

If you like, you can supply the closure wrapping via a function declaration instead of IIFE:

function createMemoizedFunc() {
    var memo;

    function f() {
      var value;
      if (memo) { value = memo.cloneNode(); }
      else {
        var value = document.createElement("div");
        value.innerHTML = "hello";
        memo = value;
      }
      return value;
    }
    return f;
}
var create_node = createMemoizedFunc();

Upvotes: 1

Patrick
Patrick

Reputation: 6948

Since functions in javascript are an object, you can just use that function to memoize the value. I think it would make more sense in fib example, but here is your original post.

function main() {
  // memoizing function
  function create_node() {
    var value;
    // read from memo on function object
    if (create_node.memo) {
      value = create_node.memo.cloneNode();
      value.innerHTML = 'cloned';
      console.log("clone node");
      console.log(value);
    } else {
      var value = document.createElement("div");
      value.innerHTML = "hello";
      console.log("new node");
      console.log("value: " + value);
      // retain memo on the function object
      create_node.memo = value;
    }
    return value;
  }

  var collection = [];
  for (var i = 0; i < 10; i++) {
    collection.push(create_node());
  };
  // Display results
  for (var i = 0; i < 10; i++) {
    console.log(i + ". " + collection[i]);
    document.getElementById('container').appendChild(collection[i]);
  }
}

main();
<div id="container"></div>

Upvotes: 1

Related Questions