Injecting local variable to a function - Can it be done?

T

tai

Hi.

I'm looking for a way to define a function that's only effective inside
specified function.

Featurewise, here's what I want to do:

bar_plugin_func = function() { ...; setTimeout(...); ... };
wrap_func(bar_plugin_func);
bar_plugin_func(); // calls custom "setTimeout"

So while plugin developer thinks s/he's calling top-level function,
I want to hook it by somehow injecting local variable with the same
name.

Simply doing something like

;(function() { setTimeout = function() { ...my custom implementation
})();

is not ideal, as that'll taint global scope. Actually, I can live with
that for now,
but it's my technical interest to find a way to define it locally.
From the quote in following reference, it says:

- http://www.unix.org.ua/orelly/web/jscript/ch11_05.html
Variable Scope
We saw above that top-level variables are implemented as properties of the current window
or frame object. In Chapter 6, Functions, we saw that local variables in a function are
implemented as transient properties of the function object itself.

So how can I manipulate "transient properties of the function object
itself"?

Thanks in advance.
 
T

tai

Perhaps some more clarification would be in order?

OK...let me try again.

I'm currently developing a JS-based framework that handles
user-registered functions. Just before executing these registered
functions, the framework redefines, or newly defines several
"top-level" methods to coordinate interaction between each
registered functions. So it's not limited to "setTimeout" method only.

Here's somewhat different, but more concrete example.
One of my framework components is FSM (finite state machine)
class, and it can be used in following manner:

var func0 = function func0(arg) { alert("func0"); goto(func2);
alert("notreached") };
var func1 = function func1(arg) { alert("func1"); goto(-1) };
var func2 = function func2(arg) { alert("func2"); goto(-1, true) };

var sm = new StateMachine(func0, func1, func2);
sm.start(func0, arg); // alerts in order of: func0, func2, func1

In above example, the framework defines "goto" method, which
cause a immediate transition to specified state. And this is
where my initial question comes in.

To provide "goto" or any other external functions, I currently
add them to global scope. However, I feel that's an overkill -
these just need to be effective in registered functions. I want
to use them as if they are "top-level", but I also want global
namespace kept clean.

I know JS's scoping rule will make any attempt void once these
registered functions do a nested function call (which resets
scope chain). However, how about directly inside these registered
functions? Is it possible to re-define top-level functions just
directly inside these (= func0, func1, func2) registered methods?
 
V

VK

I know JS's scoping rule will make any attempt void once these
registered functions do a nested function call (which resets
scope chain). However, how about directly inside these registered
functions? Is it possible to re-define top-level functions just
directly inside these (= func0, func1, func2) registered methods?

Other words, is it possible to re-compile run-time the execution
context? Actually JavaScript is one of few programming languages (if
not the single one at all) that allows you to do such things, but for
that you have of course to abandon the idea of working with the
compiled code itself and use new Function(strSource) instead.

By carefully tweaking and a bit memory leaking :) you can emulate
Perl-like local scope for a set of function (var visible in this
function and all functions called from within this function). But
AFAICT it doesn't help in your situation because you want the effect
for *any* random function sent to the constructor.
 
T

tai

Hmm...maybe some clever use of "eval" might solve this problem.
Say there's a method like

var replacements = { needtrap: function() { ... } };
var func0 = function() { needtrap() };

What I want to do is something like

with (replacements) { // install intercepting scope
func0();
}

Of course this won't work because scope chain gets reset when calling
func0 method. But with eval, maybe I can redefine it dynamically to

var func0 = function() { with (replacements) { func0 } };

But evaling function definition has a issue of "free"ing a binding to a
local scope at the time of initial definition. So I guess the real
solution
is to redefine it as

var func0 = function() {
with (original_func0_scope) { // preserve original scope at the
time of initial definition
with (replacements) { // install intercepting scope
// "needtrap" will be intercepted, bu others will work as
originally defined
func0;
}
}
};

which I'm not sure if it's possible or not.

Maybe I need to require registering functions to provide an API to
return such information (original_func0_scope = func0.get_scope()) ,
or just go with global override.
 
T

tai

For starters, "goto" is a reserved keyword, so you'll need a different
name for your function there.

Thanks, I simply thought "goto" was OK as JS does not have "goto" and
IE JScript accepted it - I'll change that.
Hm, this is a distinctly non-JavaScript way of going about things,
which leads me to think that you're experience in a different language
(Java, perhaps?) and are trying out techniques that may be appropriate
in a different language but are quite non-idiomatic to JavaScript.

Close, but not really. For FSM, I first started with something similar
to your example, but following two goals drove me to this state:

1. I wanted the use of this framework straightforward and transparent
2. Asynchronous operation support (like XmlHttpRequest)

For goal #1, I wanted to keep registering function look clean as
possible so they would not depend too much on this framework.
This helps porting/reusing existing functions.

And due to goal #2, I had to abandon use of "return <next>;" way
to initiate state shift - thus introduction of "goto". This is somewhat
off-topic, but things start to look interesting when you think about
integrating async op like below into FSM:

var func0 = function() {
var img = new Image(); img.src = "..."; img.onload = function() {
.... }; ...;
}
...
var sm = new StateMachine(func0, func1, ...);
sm.start(func0, arg);

But I must agree this is "quite non-idiomatic to JavaScript" like
you said, as this implementation was really tricky. OTOH, I think
I'm getting close to establishing goal #1.
var func0 = function func0(arg) { alert("func0"); goto(func2);
alert("notreached") };
var func1 = function func1(arg) { alert("func1"); goto(-1) };
var func2 = function func2(arg) { alert("func2"); goto(-1, true) };

var sm = new StateMachine(func0, func1, func2);
sm.start(func0, arg); // alerts in order of: func0, func2, func1


I would do this (if I understand you correctly) like so:

function StateMachine() {
// assumes all arguments are callable as functions -
// in real life you'll want to verify this
this.funcs = arguments;
}


StateMachine.prototype.callFunc = function(args) {
var num = -1;
if (args.length && args.length >= 1) {
num = args[0];
args = args[1];
}
if (num >= 0) {
this.callFunc(this.funcs[num](args));
}
}

// You can either pass in the functions as anonymous like so,
// or first define some functions and pass them in by name
var sm = new StateMachine(function() {
alert(1);
// return value determines next function to be called
// you can also have some logic here to decide what
// that should be
return [2];
},
function(arg) {
alert(arg);
return [-1];
},
function() {
alert(3);
return [1, 'howdy!'];
});

// then you call the number you want to start with as first item in an
array
// if you want multiple args you can pass those as a nested array
// remember in JS you can mix types in a single array
sm.callFunc([0]);
 
V

VK

tai said:
Hmm...maybe some clever use of "eval" might solve this problem.
Say there's a method like

var replacements = { needtrap: function() { ... } };
var func0 = function() { needtrap() };

What I want to do is something like

with (replacements) { // install intercepting scope
func0();
}

Of course this won't work because scope chain gets reset when calling
func0 method. But with eval, maybe I can redefine it dynamically to

var func0 = function() { with (replacements) { func0 } };

I am still not sure if I got right the architecture you are willing to
achieve, so sorry if a useless advise below.

Unless you need to run your code in JScript.NET compiled with /quick -
unless that you can always augment the function object:

<script type="text/javascript">
function CallDispatcher() {
for (var i=0; i<arguments.length; ++i) {
if (typeof arguments == 'function') {
arguments['$goto'] = new Function('window.alert('+i+');');
arguments();
}
}
}

function f1() {
if (f1.$goto) {
f1.$goto();
}
}

function f2() {
if (f2.$goto) {
f2.$goto();
}
}

function f3() {
if (f3.$goto) {
f3.$goto();
}
}


function init(arg) {
CallDispatcher(f2,f3,f1);
}

window.onload = init;
From the other side (as other poster pointed out) it looks like you are
brute force trying to emplement a structure of one language into all
another language. Usually it doesn't work or it leads to ugly and
unstable solutions. Maybe instead of code samples it would be more
helpful to see the block-schema you want to implement: so some standard
OOP solution could be suggested.
 
B

Bart Lateur

tai said:
Simply doing something like

;(function() { setTimeout = function() { ...my custom implementation
})();

is not ideal, as that'll taint global scope. Actually, I can live with
that for now,
but it's my technical interest to find a way to define it locally.

make setTimeout a (local) var?

var setTimeout = function () { .... };
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top