2011-09-24 82 views
1

我想弄清楚如何讓一個javascript函數私下跟蹤它被調用的次數。我們的目標是能夠通過做調試期間查詢在控制檯這個值func.run有一個JavaScript函數私人跟蹤它的調用次數

我第一次嘗試:

function asdf() { 
    if (!asdf.run) { 
    asdf.run = 0; 
    } else { 
    asdf.run++; 
    console.error('run: ' + asdf.run); 
    } 
    console.error('asdf.run def: '); 
    console.error(asdf.run); 
} 
asdf(); 



這就是爲什麼一個人應該總是使用一個很好的教訓 ===幾乎所有的javascript布爾值,因爲它們可能會偷偷地被 ==

+0

我覺得你忘了在你的文章中包含你的原始函數的輸出:) – acjay

+0

我不知道接受哪個答案。 –

+0

我發現這篇文章有用的時候瞭解JavaScript強制規則http://webreflection.blogspot.com/2010/10/javascript-coercion-demystified.html大部分規則是有意義的(我實際上喜歡0和「」是假的),但肯定會有一些地方會讓你感動 –

回答

3

閉包是走這裏的路:

var asdf = (function() { 
    var runs = 0; 
    var f = function() { 
     ++runs; 
     // your function here 
    }; 
    f.runs = function() { 
     return runs; 
    }; 
    return f; 
}()); 

用法:

asdf(); 
asdf(); 
asdf.runs(); // 2 
asdf(); 
asdf.runs(); // 3 

或者,你可以使用像(無恥的自我堵塞Myrtle嘲弄的框架。

+0

@Devin G羅德 - 你做的編輯很好。我避免使用多個'var'語句的原因是因爲JSLint。 Doug Crockford的推理是這樣的:「在使用塊範圍的語言中,通常建議首先在首次使用的站點聲明變量,但由於JavaScript沒有塊範圍,所以在頂部聲明所有函數的變量會更明智**建議每個函數使用一個var語句**「 – nickf

0

所以,!asdf.run是double等於運算符==的一種形式,並且我已經設置了asdf.run0所以它是錯誤的。

使用三重等於===

typeof asdf.run === "undefined"爲布爾解決了我的問題。

所以最終的可用和有用的版本:

function sdf() { 
    if (typeof sdf.run === "undefined") { sdf.run = 0; } 
    sdf.run++; 
} 

要查詢的時間sdf數量被稱爲:

sdf.run; 

要真正使這個私有變量,保護它的變化,一個將實施封閉。

1

我還沒有試過這個,但是我查了一下「JavaScript中的靜態函數變量」,並且我找到了this resource。我認爲你寫的內容和解決方案的主要區別在於如何檢測函數的第一次運行。也許你的!asd​​f.run測試不像你認爲的那樣工作,你應該使用typeof asdf.run =='undefined'來測試。

1

你第一次嘗試將正常工作,除非你已經忘記了0在JavaScript中的「falsy」的價值,所以在第一次運行和每一次運行之後!this.run將評估爲true和你else塊將永遠不會被達到。這很容易解決。

function foo() { 
    if(typeof(foo.count) == 'undefined') { 
    foo.count = 0; 
    } else { 
    foo.count++; 
    } 
    console.log(foo.count); 
} 

foo(); # => 0 
foo(); # => 1 
foo(); # => 2 
# ... 
0

好的,這裏是我想到的方法,根本不需要修改函數。

所以,如果你有這個。

function someFunction() { 
    doingThings(); 
} 

你可以添加這樣的反...

addCounter(this, "someFunction"); 

哪裏,這是你在範圍內,可以使用具有要算一個方法的對象。

下面是它的代碼。

<html> 
<head> 
    <script> 
     function someFunc() { 
      console.log("I've been called!"); 
     }; 

     // pass an object, this or window and a function name 
     function wrapFunction(parent, functionName) { 
      var count = 0, orig = parent[functionName]; 
      parent[functionName] = function() { 
       count++; 
       return orig.call(this, Array.prototype.slice(arguments)); 
      } 

      parent[functionName].getCount = function() { 
       return count; 
      }; 
     } 

     var someObj = { 
      someFunc: function() { 
       console.log("this is someObj.someFunc()"); 
      }        
     }         


     wrapFunction(this, "someFunc"); 
     wrapFunction(someObj, "someFunc"); 
     someFunc();   

     someObj.someFunc(); 
     someObj.someFunc(); 
     someObj.someFunc(); 

     console.log("Global someFunc called " + someFunc.getCount() + " time" + (someFunc.getCount() > 1 ? "s" : "")) ; 
     console.log("Global someObj.someFunc called " + someObj.someFunc.getCount() + " time" + (someObj.someFunc.getCount() > 1 ? "s" : "")) ; 
    </script>                 
</head>                   

0
//using a closure and keeping your functions out of the global scope 
var myApp = (function() { 
    //counter is a private member of this scope 
    var retObj = {}, counter = 0; 
    //function fn() has privileged access to counter 
    retObj.fn = function() { 
     counter++; 
     console.log(counter); 
    }; 
    //set retObj to myApp variable 
    return retObj; 
}()); 


myApp.fn(); //count = 1 
myApp.fn(); //count = 2 
myApp.fn(); //count = 3 
0

你不一定需要關閉。只需使用一個靜態變量。

var foo = function(){ 
    alert(++foo.count || (foo.count = 1)); 
} 


// test 
function callTwice(f){ f(); f(); } 
callTwice(foo)     // will alert 1 then 2 

callTwice(function bar(){   
    alert(++bar.count || (bar.count = 1)); 
});        // will alert 1 then 2 

第二個是一個名爲匿名函數。並注意這個語法:

var foo = function bar(){ /* foo === bar in here */ }