This is related to this
Anyway what I need is actually something slightly different I need some way of doing this:
function run(arg) {
this.ran = this.ran || false;
if (!this.ran) init;
/* code */
this.ran = true;
}
This works fine, I just want to make sure that this code works even when this in case it was called with call() or apply()
Check this out for what I'm talking about, All of the calls after the first one should all be true, no matter the context
to get full use of closures, i suggest you wrap your main function in another function that initiates the "ran" flag :
function initRun(){
var ran = ran || false;
return function(arguments){
if(ran)
{
console.log("can't run any more!");
return;
}
ran = true;
console.log("i'm running!");
/* your logic here */
}
}
var run = initRun();
then you can test it by calling your function in whatever way you want :
run();
run.call();
run.apply();
it successfully runs only once, no matter the calling method used.
The mini-downside is that you need an extra function that wraps your initial "run" function, but i think it's more reliable and elegant than to use a global flag that keeps track of your function calls
you can replace "this" by "arguments.callee". arguments.callee should always give you the object representing your current function thus isolating you from changing "this". (However I did not test^^)
When you define a free-standing function, "this" refers to the global window object. When that is the case, you might as well just use the global variable explicitly to avoid any chance of "this" from being usurped from .apply() or .call()... provided that is the desired behavior.
function run(arg) {
window.ran = window.ran || false;
if (!window.ran) init();
/* code */
window.ran = true;
}
As a side note, if you define a function as a property of an object, "this" refers to the owning object. Note that "this" is a reference to a function's owner, and the owner depends on the context.
EDIT: also, as a followup to #Anurag's suggestion, is this unsuitable?
var run = (function createRun() {
var ran = false;
return function(arg) {
if (!ran) init;
// code
ran = true;
};
})();
run(arg);
Related
I may be wording this title wrong but in javascript is it ok to call a nested function like so, if not why and what are some safer or more proper ways
function foo() {
return function poo() {
console.log("ew");
}
}
var fooPoo = foo()();
Yes, that's fine, and fairly normal, if you want poo to have access to information that's private within foo and you don't want the calling code to have access to that information. Or even just if foo is what knows how to create the poo function, even if private information isn't needed.
It's relatively rare to do it all in one expression, because usually when you return a function from another function, you want to keep the function around:
var p = foo();
var fp1 = p();
var fp2 = p();
...but only relatively unusual, not unusual.
Here's an example of using the private information held by the context of the original call to the function (allocator, here, is like your foo):
function allocator(seed) {
return function() {
return seed++;
};
}
var a = allocator(1);
console.log(a()); // 1
console.log(a()); // 2
console.log(a()); // 3
Note that the code calling a can't manipulate seed directly. It can only call a and use the value it returns.
Yes, it as a functional technique referred to as currying. it allows you to set parameters for the function in different places in your code
function foo(param1) {
return function poo(param2) {
console.log(param1, param2);
}
}
var fooPoo = foo('param1')('param2');
A common thing I do is use currying for passing in settings when running event listeners to allow greater reuse of functions
function setColor(color) {
return function (e) {
e.target.background = color
}
}
someElement.addEventLister('click', setColor('red'))
Here you can pass in your configuration when declaring your event listener but it won't be called until later when the event is fired and due to the closure you will have access to the color variable within the event listener callback. But now that I know the technique I use it quite a bit
I have a simple javascript error logging mechanism in place and it looks somewhhat like this:
window.onerror = function (ErrorMsg, Url, LineNumber, Col, Error) {
// ajax these to the server, including Error.stack}
The problem is that I'd also like to get the value of the local variables and function parameters when the error occurred. Is this even possible?
I'm thinking about modifying the Function prototype so that each time a function runs, its arguments are stored in a global array of strings and then the error handler would just add this array to the ajax call. Can JavaScript do this?
#1 Can local scope be recovered in onerror() without black magic?
Without this being bound in the scope of window.onerror() or the surrounding variables being directly accessible, it's impossible to regain access to the variables you had set.
What you're mostly wanting access to is this.arguments or arguments or the equivalent, but that's destroyed. Any hope of obtaining a key-value associative array or hash-like object would involve meta-programming ( i.e. reading the function definition to obtain the variable names, and obtaining an exception report to attempt to salvage data ).
See this answer for more on something similar:
Getting All Variables In Scope
But this "lacking functionality" is a good thing:
If you could gain access to what you're asking for, that would likely be a fault in the Javascript engine. Why? Because the variable states and contents themselves are what caused the exception/error, assuming bad code wasn't the issue to begin with.
In other words, if you could get access to a faulty variable, that might be a door into an infinite loop:
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Failure due to variable contents.
Error handler triggered.
Trace contents of variable.
Etc.
#2 Can Javascript store all arguments of every function call by voodoo?
Yes. It can. This is probably a really bad idea ( see #1 ) but it is possible. Here is a pointer on where to start:
Is there a way to wrap all JavaScript methods with a function?
From there, what you're wanting to do is push this.arguments or equivalent to a stack of function calls. But again, this is approaching insanity for many reasons. Not the least of which is the need to duplicate all the values, lest you reference mutated variables, or be unable to access the data at all... and like I said above, the problem of bad data in general. But still, it is possible.
Is this even possible?
No. A stack trace is proof that the stack has unwound, all stack frames and all the local variables they contained are gone. As for getting the name of a variable, that is not even possible at run time.
To start off i accept #Tomalak completely.
I was also put in your situation where i needed to debug a remote running app in case of crash.
As a work around I have forked my code for you in a fiddler. Please modify according to your need.
Caveat: You have to wrap the function body with try{..}catch(e){..} as illustrated in the fiddler code.
Please read the inline comments for understanding.
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
console.log(errorObj);
}
window.addEventListener("reportOnError", function(e){
console.log(e.detail);
/*Send to the server or any listeners for analysis.*/
//Http.send(e.detail);
});
function ExceptionReport(ex, args, scope) {
var self = {};
self.message = ex.message;
self.stack = ex.stack;
self.name = ex.name;
self.whoCalled = args.callee.caller.name == "" ? "Window": args.callee.caller.name;
self.errorInFunction = args.callee.name;
self.instanceOf = scope.constructor;
self.KeyPairValues = getParamNames(arguments.callee.caller.toString(), Array.prototype.slice.call(args)); //Contains the parameters value set during runtime
window.dispatchEvent(new CustomEvent('reportOnError', {'detail':self}));
}
//Utilties
function getParamNames(fnBody, values) {
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,
ARGUMENT_NAMES = /([^\s,]+)/g,
result = fnBody.slice(fnBody.indexOf('(')+1, fnBody.indexOf(')')).match(ARGUMENT_NAMES),
obj={};
fnBody.replace(STRIP_COMMENTS, '');
if(result !== null){
for(var i=0; i < result.length; i++){
obj[result[i]] = values.length !==0 ? values[i] : null;
}
}else{
obj = null;
}
return obj;
}
/*
This is a testing/sample function that throws the error
*/
function testing(a,b,c){
try{
dummy(1,2) ; //This line throws the error as reference error.
}catch(e){
ExceptionReport(e, arguments, this);
}
}
//Class Emulation: For instanceof illustration.
function testingClass(){
this.testing = testing;
}
//Named self executing function: This calls the function
var myvar = (function myvar(){
testing(1,2,3);
})();
//Illustrating instanceof in exception
var myVar2 = new testingClass();
myVar2.testing(1,2,3);
//Calling from global scope this is Window
testing(1,2,3);
//Without variables
testing();
I have used examples to illustrate the behavior of functions called in different circumstances.
Below signifies the varialble used for
self.KeyPairValues : Used to store the function parameter set/passed during runtime
self.errorInFunction : This stores the name of the function error was caused in.
self.whoCalled : This stores the function name that invoked the defective function
self.instanceOf : This stores the name of the instance is called creating a new instance.
Other variables are same as in Error object
The others answers here are spot on, but I might be able to offer a suggestion for a slightly different way to accomplish this. Instead of trying to track all scope in your program, why not add a tagging function that tracks the scope of one function's parameters without affecting the runtime of the function. For for example:
var globalRecord = {};
function record(name, fn) {
return function () {
var args = [].slice.call(arguments);
var record = globalRecord[name] = {
args: args,
arg: {}
};
args.unshift(function (name, value) {
return record[name] = value;
});
fn.apply(args, arguments);
}
}
// Then, you track variables like this
var func = record("func", function (record, a, b, c) {
record("a", a); // named parameters are accessible now
record("b", b); // if some error occurs in the function body
return a + b + c;
});
// Calling func still behaves as before.
func(1, 2, 3);
// Errors handled like this:
window.onerror = function () {
globalRecord.func.args; // ==> last set of arguments past to function
globalRecord.func.arg.a; // specific arguments recorded with names
};
You could even use this method to track scope without using a function by anonymously calling the recorded function.
record("test", function (record) {
var a = record("a", /* whatever */);
var b = record("b", /* ... */ );
// do scope specific stuff that might fail
})();
Of course, this isn't a polished implementation by any stretch, but with a little work, I think you might be able to get the behavior you're looking for without any seriously black magic. By selectively adding and removing record calls as the need presents itself, you can have precise control over what is logged without any intrusive hacks.
You can find your answer in this link.
Before taking bundles from the server, you must modify them. For example, to solve your problem, you can do changes in the mentioned link as follows. In the BuildBundleContent Class make this change:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, this){1}",
errVariable, hasContent ? ";" : ""));
If in the modules you have to use something like:
var self = this;
You can use:
contents.Insert(blockContentIndex,
string.Format("if(customErrorLogging)customErrorLogging({0}, self ? self : this){1}",
errVariable, hasContent ? ";" : ""));
And in added js file:
"use strict";
var customErrorLogging = function (ex, module) {
console.log(module);
//do something...
};
I hope help you.
I dont understand one thing:
var comein = document.getElementById("comein");
var enter = new Expand({ elem : comein });
function Expand (options) {
this._elem = options.elem;
console.log(this._elem); // i have a div element
}
Expand.prototype = {
check : function () {
var comInClassName = this._elem.className; // i have an error: this._elem is undefined
if (comInClassName == "open"){
this.close();
}
if (comInClassName == "close"){
this.open();
}
}
}
log_in.addEventListener("click", enter.check, false);
Why I have an error in prototype method if in Expand i have a normal element? Thanks
It depends entirely on how you call check. If you call it like this:
enter.check();
....then within the call, this will refer to the enter object and it will have an _elem property. If, on the other hand, you set it up to be called like this:
enter._elem.addEventListener('click', enter.check, false);
...then within the call (when the event occurs), this will not refer to enter, but rather to this._elem, and so it has no _elem property.
This happens because in JavaScript (for now), this within a function call is defined entirely by how the function is called, not where the function is defined. If you call it as part of an expression retrieving the function reference from an object:
enter.check();
...then this refers to the object you got the function reference from. But if you call it separately, as with the addEventListener call above, it doesn't.
If you're on an ECMAScript5-enabled environment (or if you have a decent ES5 shim in place), you can fix that by using Function#bind:
enter._elem.addEventListener('click', enter.check.bind(enter), false);
bind returns a function that, when called, will turn around and call the underlying function using the given this value (enter, in our case).
More to explore (on my blog):
Mythical Methods
You must remember this
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Javascript OOP return value from function
I have a class defined like this
function SocialMiner(tabUrl)
{
var verbose=true;
var profileArray=new Array();
this.tabUrl=tabUrl;
this.getTabUrl=function(callback)
{
chrome.tabs.getSelected(null, function(tab)
{
callback(tab.url);
});
}
this.setTabUrlValue=function(pageUrl)
{
this.tabUrl=pageUrl;
console.log("22"+this.tabUrl); //this statement shows url correctly
}
}
When I call this method like these
miner.getTabUrl(miner.setTabUrlValue);
miner.logToConsole("1"+miner.tabUrl); //This statement returns undefined
The console.log inside callback correctly outputs url , however, the tabUrl property of miner ojbect is undefined , as seen in second console.log. Why is it so ?
The solution is to save a reference to this within the constructor (available later on via closure):
var that = this; //in the top of the SocialMiner constructor function
and in setTabUrlValue use:
that.tabUrl=pageUrl;
I suspect running a method as a function (callback) loses scope, i.e. doesn't know of any this anymore. In other words, it runs within the scope of the constructor, not as a method of the instance using it. A variable referencing this in the constructor scope is available to the function, and that points to the right this on instance creation.
You could also force callback to run in the current instance scope like this:
callback.call(this,tab.url);
In that case you can leave this.tabUrl=pageUrl; as it is.
This is an simplification of your code. The methods return this to be able to directly reference a property of the instance (see console.log last line):
function Some(){
var that = this; // note: not used in this example
this.getA = function(callback){
someval = 'foobar';
callback.call(this,someval);
return this;
};
this.getB = function(val){
this.val = val;
return this;
};
}
var some = new Some;
console.log( some.getA(some.getB).val ); //=> foobar
Taking a look # your code again, I think you're loosing scope twice, because callback is called from within another callback. That's why I think your code on that spot should be:
chrome.tabs.getSelected(
null,
function(tab) {
callback.call(that,tab.url); //< use that here
}
);
Furthermore, in you code # github, I don't see any instantiation of the miner instance.
this is a tricky beast in JavaScript and as others have pointed out is the key to the issue. The problem with using this everywhere is that it's value can change depending on who/where the function is called from (for example, see the call and apply methods in JavaScript). I'm guessing that if you wrote the value of this to the console in the the callback from the chrome.tabs.getSelected function you'd find it isn't your miner any more.
The solution is to capture a reference to the this that you're actually interested in when you know for sure it's the right one & then use that reference from then on. Might make more sense to see it commented in-line in your example:
function SocialMiner(tabUrl)
{
//At this point we know "this" is our miner object, so let's store a
//reference to it in some other (not so transient) variable...
var that = this;
var verbose=true;
var profileArray=new Array();
this.tabUrl=tabUrl;
this.getTabUrl=function(callback)
{
chrome.tabs.getSelected(null, function(tab)
{
//at this point "this" is whatever the "chrome.tabs.getSelected"
//method has decided it is (probably a reference to the tab or something)
callback(tab.url);
});
}
this.setTabUrlValue=function(pageUrl)
{
//because this can be called from anywhere, including the chrome callback
//above, who knows what "this" refers to here (but "that" is definitely
//still your miner)
that.tabUrl=pageUrl;
console.log("22"+that.tabUrl);
}
}
You can see how much this shifts around in libraries that use callbacks heavily like jQuery, where often this is set to convenient values, but certainly not the same this that was logically in scope when you made the initial call.
EDIT: Looking at the full source (& example) you posted, this is just a timing issue where obviously the chrome.tabs.getSelected is returning asynchronously after your "second" call to log goes through...
console.log("5");
miner.getTabUrl(miner.setTabUrlValue); //setTabUrlValue is logging with '22'
console.log("6");
miner.logToConsole("1"+miner.tabUrl);
console.log("7");
// Output:
5
6
1 undefined //the chrome.tabs.getSelected hasn't returned yet...
7
22 http://url //now it has (so if you tried to use miner.tabUrl now you'd be all good...
The solution is to put all the stuff after the get/set into the callback, since you don't want anything happening until after that tabUrl is finished being set... so something like this:
console.log("5");
miner.getTabUrl(function(pageUrl) {
miner.setTabUrlValue(pageUrl);
console.log("6");
miner.logToConsole("1"+miner.tabUrl);
console.log("7");
});
Hopefully that will see you getting your results in the order you expect them.
I think this happens because closure vars do not survive a function call.
I'm trying to mimic static variables on a JavaScript function, with the following purpose:
$.fn.collapsible = function() {
triggers = $(this).children('.collapse-trigger');
jQuery.each(triggers, function() {
$(this).click(function() {
collapse = $(this).parent().find('.collapse');
})
})
}
How do I save the "collapse" object so it doesn't have to be "found" on each call? I know that with named functions I could do something like "someFunction.myvar = collapse", but how about anonymous functions like this one?
Thanks!
You can save your variable in the function, using either functioName.myVar = value or arguments.callee.myVar = value if you don't have the current function name.
arguments.callee is the current function you are in.
For anonymous function you could use a function that returns a function.
For instance:
var myAnonymousFunction = (function(){
var myFirstStatic = $("#anElement");
var anotherStatic = true;
return function(param1,param2) {
// myFirstStatic is in scope
// anotherStatic also
}
})();
Should work like a charm and you're assured initialisation code for statics is only executed once.
It seems that a better answer to this question is found elsewhere on Stack Overflow.
In short, you can actually give anonymous functions names without polluting the namespace, yet still allow self-referencing.
mything.prototype.mymethod = function myKindOfFakeName() {
myKindOfFakeName.called = true;
}
As long as you're assigning the function to a variable like that, you should be able to access it as $.fn.collapsible, and thus assign variables as $.fn.collapsible.myvar.