Caution Javascript Closure in Loop

Posted in code with : javascript


Object

Define a function addTimer, to log executed time for all function-type property of an object

Definition 1

Code:

 1 var addTimer = function (widget) {
 2     var prop;
 3     for (prop in widget) {
 4         if (typeof widget[prop] === 'function') {
 5             var backupFunc = widget[prop];
 6             // the same problem with the following code
 7             //backupFunc = (function () {
 8             //    return widget[prop];
 9             //})();
10             
11             // try a deep copy here to make bakcupFunc not changed with prop
12             widget[prop] = function () {
13                 console.time("from timer " + prop);
14                 backupFunc.apply(this, arguments);
15                 console.timeEnd("from timer " + prop);
16             };
17             // the same problem with the following code
18             //widget[prop] = (function () {
19             //    return function () {
20             //        console.time(prop);
21             //        backupFunc.apply(this, arguments);
22             //        console.timeEnd(prop);
23             //    };
24             //})();
25         }
26     }
27 }

Problem

All function type property in widget will call the last function type property

Definition 2

Since there is no block scope in JavaScript - only function scope - by wrapping the function creation in a new function, you ensure that the value of prop remains as you intended.

Code:

 1 var addTimer = function (widget) {
 2     var prop;
 3     var getFuncWithTimer = function (prop) {
 4         return function () {
 5             console.time("from timer " + prop);
 6             widget[prop].apply(this, arguments);
 7             console.timeEnd("from timer " + prop);
 8         };
 9     };
10     for (prop in widget) {
11         if (typeof widget[prop] === 'function') {
12             widget[prop] = getFuncWithTimer(prop);
13         }
14     }
15 };

Problem

exceed maximum call stack

Definition 3

Code:

 1 var addTimer = function (widget) {
 2     var prop;
 3     var getFuncWithTimer = function (prop) {
 4         var backupFunc = widget[prop];
 5         return function () {
 6             console.time("from timer " + prop);
 7             backupFunc.apply(this, arguments);
 8             console.timeEnd("from timer " + prop);
 9         };
10     };
11     for (prop in widget) {
12         if (typeof widget[prop] === 'function') {
13             widget[prop] = getFuncWithTimer(prop);
14         }
15     }
16 };

Problem

All function with returned value can not work

Final Definition

Code:

 1 var addTimer = function (widget) {
 2     var prop;
 3     var getFuncWithTimer = function (prop) {
 4         var backupFunc = widget[prop];
 5         return function () {
 6             console.time("from timer " + prop);
 7             var ret = backupFunc.apply(this, arguments);
 8             console.timeEnd("from timer " + prop);
 9             return ret;
10         };
11     };
12     for (prop in widget) {
13         if (typeof widget[prop] === 'function') {
14             widget[prop] = getFuncWithTimer(prop);
15         }
16     }
17 };