admin管理员组文章数量:1433496
I'm trying to figure out how I can have a javascript function privately track the number of times it has been called. The objective is to be able to query this value in the console during debugging by doing func.run
My first attempt:
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();
This is a good lesson of why one should ALWAYS aim to use
===
in nearly all javascript booleans, cause they could secretly be ==
I'm trying to figure out how I can have a javascript function privately track the number of times it has been called. The objective is to be able to query this value in the console during debugging by doing func.run
My first attempt:
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();
This is a good lesson of why one should ALWAYS aim to use
===
in nearly all javascript booleans, cause they could secretly be ==
Share
Improve this question
edited Sep 24, 2011 at 5:21
Devin Rhode
asked Sep 24, 2011 at 4:57
Devin RhodeDevin Rhode
25.4k8 gold badges68 silver badges84 bronze badges
3
- I think you forgot to include the output of your original function in your post :) – acjay Commented Sep 24, 2011 at 5:08
- I have no idea which answer to accept. – Devin Rhode Commented Sep 24, 2011 at 5:27
- I found this post helpful when learning about javascript coercion rules webreflection.blogspot./2010/10/… most of the rules make sense (I actually like that 0 and "" are falsey), but there are definately some areas that will trip you up – Matt Briggs Commented Sep 24, 2011 at 5:33
7 Answers
Reset to default 4Closures are the way to go here:
var asdf = (function () {
var runs = 0;
var f = function () {
++runs;
// your function here
};
f.runs = function () {
return runs;
};
return f;
}());
Usage:
asdf();
asdf();
asdf.runs(); // 2
asdf();
asdf.runs(); // 3
Or, you could use a mocking framework like (shameless self plug) Myrtle.
Your first try would work fine except you've forgotten that 0
is a "falsy" value in JavaScript, so on the first run and every run thereafter !this.run
will evaluate to true
and your else
block will never be reached. This is pretty easy to work around.
function foo() {
if(typeof(foo.count) == 'undefined') {
foo.count = 0;
} else {
foo.count++;
}
console.log(foo.count);
}
foo(); # => 0
foo(); # => 1
foo(); # => 2
# ...
I haven't actually tried this, but I looked up "static function variables in JavaScript", and I found this resource. I think the main difference between what you wrote and what's in that solution is how the first run of the function is detected. Perhaps your !asdf.run test is not working the way you thought it was, and you should use typeof asdf.run == 'undefined' to test instead.
OK, here is a method that I came up with that does not require the function to be modified at all.
So if you have this.
function someFunction() {
doingThings();
}
you could add a counter like this...
addCounter(this, "someFunction");
where this is the scope you are in, you could use any object that has a method you want to count.
Here's the code for it.
<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>
So, !asdf.run
is a form of the double equals operator ==
and I had set asdf.run
to 0
so it was false.
Using the triple equals ===
:
typeof asdf.run === "undefined"
for the boolean solves my issue.
So a final usable and useful version:
function sdf() {
if (typeof sdf.run === "undefined") { sdf.run = 0; }
sdf.run++;
}
To query the number of times sdf
has been called:
sdf.run;
To actually make this variable private and protect it from change, one would implement a closure.
//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
You don't necessarily need a closure. Just use a static variable.
var foo = function(){
alert( ++foo.count || (foo.count = 1) );
}
// test
function callTwice(f){ f(); f(); }
callTwice(foo) // will alert 1 then 2
or
callTwice( function bar(){
alert( ++bar.count || (bar.count = 1) );
}); // will alert 1 then 2
the second one is a named anonymous function. And note this syntax:
var foo = function bar(){ /* foo === bar in here */ }
本文标签: closuresHave a javascript function privately track it39s number of callsStack Overflow
版权声明:本文标题:closures - Have a javascript function privately track it's number of calls - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745612148a2666176.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论