473,416 Members | 1,731 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,416 software developers and data experts.

JavaScript Variable Interpolation, Take II

(Note: This is not the same message I posted a week or so ago. The
problem that prevented my previous attempt to work was a silly error in
the template system I was using. This is a problem involving variable
scope in JavaScript.)

I have a lot of code that generates HTML on the fly. This code has tags
with id attributes derived from variables. A small example:

blah('<span id="' + dev + '_' + mod + '">...</span>');

This is ugly, and in the typical more complicated cases rapidly becomes
an unreadable mess. What I want is a facility like in Perl, where I can
interpolate the value of variables. It might look like this:

blah('<span id="{dev}_{mod}">...</span>');

That is, whenever I see a string between curly brackets, I want to
replace that with the value of that variable.

So I wrote this function:

function XXX(s) {
return s.replace(
/\{([^}]+)\}/g,
function (dummy, v) {
return eval(v);
}
);
}

And it works... kinda. Here's an example:

x = 42;
y = "hello world";
z = {bobo: true};
alert(XXX("x,y,z.bobo: {x}, {y}, {z.bobo}"));

And yes, an alert box pops up with "x,y,z.bobo: 42, hello world, true"
displayed, as I wanted.

But there is a problem. This doesn't work:

function whatever(example) {
return XXX("example is {example}");
}

alert(whatever(42));

If you run this, it won't work. And the reason is clear: JavaScript is
evidently a lexically instead of dynamically scoped language. Okay, so
what I want is a way to evaluate in the context of the string I'm
passing in to XXX. I tried this slight change:

function XXX(s) {
return s.replace(
/\{([^}]+)\}/g,
function (dummy, v) {
return s.eval(v);
}
);
}

(The change: I tried "s.eval" instead of just "eval" in an attempt to
forced evaluation in the context of the string.) But it doesn't work.

So what I'm asking the experts here is how can I write my variable
interpolator so that it works as I've described. Or alternatively, if
an example of this exists in a JavaScript library, please point me to
that library.
May 28 '07 #1
10 12753
VK
On May 28, 12:23 pm, John Passaniti <put-my-first-name-
h...@JapanIsShinto.comwrote:
But there is a problem. This doesn't work:

function whatever(example) {
return XXX("example is {example}");
}

alert(whatever(42));

If you run this, it won't work. And the reason is clear: JavaScript is
evidently a lexically instead of dynamically scoped language.
I don't think I agree with such interpretation. Javascript implements
global scope and local scopes within functions. Evidently by creating
a local variable inside one function you do not automatically affect
local scopes of other functions, otherwise that would be disastrous. I
do not recall any other languages acting in opposite. You have to take
some explicit actions to inform the engine that you need this or that
local value also available in some other local context connected by
the call chain with the current context. Say in Perl you have to
declare then your value as "local" instead of "my". In Javascript you
have two options:

1) Temporary local context transfer from caller to callee:

<script>

function primary(arg1, arg2) {
window.alert(arg1 + ' ' + arg2);
}

function secondary() {
primary.apply(null, arguments);
// or (this, arguments) if within
// an object instance
}

secondary('Hello', 'world!')
</script>

2) By nesting local scopes using closures. The latter is a really
dangerous doing because of possible memory leaks, but if properly done
then OK

<script>

function outer(arg1, arg2) {

inner();

function inner() {
window.alert(arg1 + ' ' + arg2);
}
}

outer('Hello', 'world!');
</script>

May 28 '07 #2
John Passaniti wrote:
(Note: This is not the same message I posted a week or so ago. The
problem that prevented my previous attempt to work was a silly error in
the template system I was using. This is a problem involving variable
scope in JavaScript.)

I have a lot of code that generates HTML on the fly. This code has tags
with id attributes derived from variables. A small example:

blah('<span id="' + dev + '_' + mod + '">...</span>');

This is ugly, and in the typical more complicated cases rapidly becomes
an unreadable mess. What I want is a facility like in Perl, where I can
interpolate the value of variables. It might look like this:

blah('<span id="{dev}_{mod}">...</span>');

That is, whenever I see a string between curly brackets, I want to
replace that with the value of that variable.
So what I'm asking the experts here is how can I write my variable
interpolator so that it works as I've described. Or alternatively, if
an example of this exists in a JavaScript library, please point me to
that library.
See the supplant method in http://javascript.crockford.com/remedial.html
May 28 '07 #3
Douglas Crockford wrote:
See the supplant method in http://javascript.crockford.com/remedial.html
Thanks. It isn't quite what I wanted since it can only do the string
replacement from an explicitly-passed object. That gets rid of the
scoping issues, but it is far more restrictive.
May 28 '07 #4
VK wrote:
I don't think I agree with such interpretation. Javascript implements
global scope and local scopes within functions. Evidently by creating
a local variable inside one function you do not automatically affect
local scopes of other functions, otherwise that would be disastrous. I
do not recall any other languages acting in opposite.
I'm not asking that local scope of the caller *override* local scope of
the callee. What I'm looking for is a way to make the caller's locals
be *visible* without me passing explicit context. The mechanism for
visibility can be anything. As for what languages offer this, some
flavors of Lisp come to mind as well as Lua prior to version 5.0. If
dynamic scoping in those languages is a good thing is a different question.

Thanks for your solutions, but I'm still stuck with the notion that what
I want can be done without explicitly passing arguments or by using
closures. I note that function objects can apparently access context of
their callers, but this appears to be non-portable across versions of
JavaScript.

Oh well, for now I'll just hack around the problem. Thanks for your reply.
May 28 '07 #5
On May 28, 10:25 am, John Passaniti <put-my-first-name-
h...@JapanIsShinto.comwrote:
Douglas Crockford wrote:
See the supplant method inhttp://javascript.crockford.com/remedial.html

Thanks. It isn't quite what I wanted since it can only do the string
replacement from an explicitly-passed object. That gets rid of the
scoping issues, but it is far more restrictive.
String.prototype.interp = function ( vMap )
{
return this.replace( /\{([^}]+)\}/g,
function ( dummy, v ) {
return vMap( v );
} );
};

function test( example ) {
var
vMap = function ( _x_ ) { return eval( _x_ ); },
x = 42,
y = "hello world",
z = { bobo : true},
q = "x: {x}, y: {y}, z.bobo: {z.bobo}, example: {example}"
;
alert( q.interp( vMap ) );
}
test("#1" );

--
../rh

May 29 '07 #6
ro********@gmail.com wrote:
String.prototype.interp = function ( vMap )
Thanks for the code. That's closer to my ideal, but still requires
creating an explicit closure to capture the context. I'll continue to
try to find a way that's closer to what I want.
May 29 '07 #7
On May 28, 10:46 pm, John Passaniti <put-my-first-name-
h...@JapanIsShinto.comwrote:
ron.h.h...@gmail.com wrote:
String.prototype.interp = function ( vMap )

Thanks for the code. That's closer to my ideal, but still requires
creating an explicit closure to capture the context. I'll continue to
try to find a way that's closer to what I want.
If I understand, then, you wish to have the execution context
available in order to interpolate, but you also wish to do so neither
exclusively within the opening execution context, nor through creation
of a closure in order to re-establish the context.

There's a reason that var's within the execution context are referred
to as "private variables". The only access to private variable values
is from within the execution context, or through a method call from
within the execution context that passes the values (or references)
out. Where the latter would seem to fit more closely with Douglas
Crockford's "supplant" method, you've already rejected that as being
"restrictive".

Seems to me that doesn't leave much room to "find a way that's closer
to what I want", no matter how much you may want it. ;-)

--
../rh

May 29 '07 #8
ro********@gmail.com wrote:
If I understand, then, you wish to have the execution context
available in order to interpolate, but you also wish to do so neither
exclusively within the opening execution context, nor through creation
of a closure in order to re-establish the context.
Correct, the ideal is to have what is offered in other languages that
offer variable interpolation built-in to the language. Perl is one example:

sub whatever {
my $example = 42;
return "example is: $example";
}

That is what I am trying to emulate.
There's a reason that var's within the execution context are referred
to as "private variables". The only access to private variable values
is from within the execution context, or through a method call from
within the execution context that passes the values (or references)
out. Where the latter would seem to fit more closely with Douglas
Crockford's "supplant" method, you've already rejected that as being
"restrictive".
I fully understand that yes, private variables are (and should be)
private. And normally, that is exactly what I want in the code I write.
Lexical scoping rules work for me 95% of the time.

This is a 5% case. This is a case where I find JavaScript is missing
some functionality I find useful, and I am looking for a way to emulate
it. So I am asking not for approval, but creativity from JavaScript
programmers who are more experienced than I to think of a solution. If
there is none, fine. But I have to believe that there is likely some
solution given the tools JavaScript already provides.
Seems to me that doesn't leave much room to "find a way that's closer
to what I want", no matter how much you may want it. ;-)
Actually, I think I'm coming closer to a solution. I haven't
implemented it yet, so here is a description.

My problem has been the explicit creation of a closure to capture the
context. The whole point of this exercise is to reduce the amount of
code I have to write when I want to interpolate variables into strings,
and setting up an explicit closure is just as ugly as streams of
literals and variables being concatenated.

It's the creation of an *explicit* closure that I dislike, not the use
of closures at all. So the question now is if there is a way to do this
implicitly.

One way may be to change this from a function call to an object
creation. That is, instead of this:

var example = 42;
alert(interpolate("example is: {example}"));

I think syntax like this may be possible:

var example = 42;
alert(new Interpolate("example is: {example}"));

The difference is that I would be creating an instance of Interpolate in
the same context. If I can have the constructor build a closure, it may
serve my needs. I'll play with this later and if anything useful comes
out, I'll post it here.
May 31 '07 #9
VK
On May 31, 8:35 am, John Passaniti <put-my-first-name-
h...@JapanIsShinto.comwrote:
This is a 5% case. This is a case where I find JavaScript is missing
some functionality I find useful, and I am looking for a way to emulate
it.
Another option would be to install free ActivePerl and then use Perl
in <scriptblocks instead of javascript:
http://www.activestate.com/products/activeperl/
Obviously it fits only for local solutions as Web-wide one cannot
expect ActivePerl installed on each visitor. Still if you are making a
solution for some organization and if Perl is your primary development
language then ActivePerl could be a good time-saving option.

Concerning the string interpolation functionality you are seeking for:
indeed Javascript completely misses it. Actually in the aspect of
string manipulations any language is very weak in comparison with
Perl: because Perl was made for it and for years hundreds of
developers were adding into it anything what could improve and/or
simplify string manipulations. And the core is of course Perl's
concept of non-interpolated strings in single quotes:
'Non-interpolated string';
and run-time interpolated strings in double quotes:
"Run-time interpolated string";

Neither Javascript nor any other widely used language I'm aware of has
this functionality. So my suggestion would be to simply use Perl
client-side as well. Any emulations using RegExp tricks will be
forcedly ugly and unnecessarily resource intensive. If client-side
Perl is not an option than I would use the standard OOP solution with
request object, its fields and methods:

function DB() {
this.FROM = '';
this.WHERE = '';
this.data = '';
this.setQuery = DB.setQuery;
}
DB.setQuery = function() {
// combine query from this.FROM and this.WHERE
// and send request
}

var myDB = new DB;
DB.FROM = 'foo';
DB.WHERE = 'bar';
DB.setQuery();

That is not by any means a functional solution, it is just a hint of
the way to do things if you decide to stay with Javascript. Because if
you stay with Javascript then you have to force yourself onto OOP
thinking sooner the better; otherwise you'll keep hitting missing
functionality here and there and keep being frustrated by your code
and nostalgic about Perl :-) IMHO it is better to make one painful
switching effort rather than prolong the suffer :-)

Jun 2 '07 #10
On May 30, 9:35 pm, John Passaniti <put-my-first-name-
h...@JapanIsShinto.comwrote:
ron.h.h...@gmail.com wrote:
If I understand, then, you wish to have the execution context
available in order to interpolate, but you also wish to do so neither
exclusively within the opening execution context, nor through creation
of a closure in order to re-establish the context.

Correct, the ideal is to have what is offered in other languages that
offer variable interpolation built-in to the language. Perl is one example:

sub whatever {
my $example = 42;
return "example is: $example";
}

That is what I am trying to emulate.
Understood from the original description of what you wanted.
There's a reason that var's within the execution context are referred
to as "private variables". The only access to private variable values
is from within the execution context, or through a method call from
within the execution context that passes the values (or references)
out. Where the latter would seem to fit more closely with Douglas
Crockford's "supplant" method, you've already rejected that as being
"restrictive".

I fully understand that yes, private variables are (and should be)
private. And normally, that is exactly what I want in the code I write.
Lexical scoping rules work for me 95% of the time.

This is a 5% case. This is a case where I find JavaScript is missing
some functionality I find useful, and I am looking for a way to emulate
it. So I am asking not for approval, but creativity from JavaScript
programmers who are more experienced than I to think of a solution. If
there is none, fine.
You'll see the experts using

setTimeout(function() {..}, 500)

, perhaps not the prettiest of structures, to generate a closure for
use on expiry of the timer.

You sort of had the answer originally when you stated: "And the reason
is clear: JavaScript is evidently a lexically instead of dynamically
scoped language."

There is a form of dynamic scoping of object property reading through
the prototype chain mechanism, as program execution changes to objects
on the prototype chain can affect property resolution.

Nonetheless, for closures, the function to which a reference is held
to maintain a closure on the execution context and related scoping
chains, has the requirement that it be lexically scoped into the
environment in which it is to be utilized.
>But I have to believe that there is likely some
solution given the tools JavaScript already provides.
Seems to me that doesn't leave much room to "find a way that's closer
to what I want", no matter how much you may want it. ;-)

Actually, I think I'm coming closer to a solution. I haven't
implemented it yet, so here is a description.

My problem has been the explicit creation of a closure to capture the
context. The whole point of this exercise is to reduce the amount of
code I have to write when I want to interpolate variables into strings,
and setting up an explicit closure is just as ugly as streams of
literals and variables being concatenated.
While it's easy to see the ideal, surely you don't equate introduction
of a relatively succinct function expression to being "as ugly as
streams of literals and variables being concatenated."
It's the creation of an *explicit* closure that I dislike, not the use
of closures at all. So the question now is if there is a way to do this
implicitly.

One way may be to change this from a function call to an object
creation. That is, instead of this:

var example = 42;
alert(interpolate("example is: {example}"));

I think syntax like this may be possible:

var example = 42;
alert(new Interpolate("example is: {example}"));
Which is conserving in phrasing, albeit misleading and possibly error-
prone to omission of "new", and really not all that far off from:

alert( "example is: {example}".interp( function(_){return
eval(_);}) );

In the latter, nonetheless, one would be inclined to use a function
reference if more than a one-off use was required.

Neither form, however, would come that close to meeting the ideal of a
language-based facility for performing string interpolation. It can be
done, because of Javascript's flexibility, but it's a question of
what's the cost. It appears to be not as unencumbered as one might
hope.
The difference is that I would be creating an instance of Interpolate in
the same context. If I can have the constructor build a closure, it may
serve my needs. I'll play with this later and if anything useful comes
out, I'll post it here.
A fine conditional. Success is awaited, in dubiousness ever so. ;)

--

../rh

Jun 4 '07 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Peter Horst | last post by:
I have a tiny custom 404 script I'm working on; I'd like to imitate the standard Apache 404 page insofar as I'd like "Apache/1.3.29 Server at www.example.com Port 80" to appear below my 404...
3
by: red | last post by:
within an object function, this code: $test2='test'; echo "$test"; $this->test2='test2'; echo "$this->test2\n"; produces this result: test2
7
by: bartek | last post by:
Hello, I've been pondering with this for quite some time now, and finally decided to ask here for suggestions. I'm kind of confused, actually... Maybe I'm thinking too much... Brain dump...
14
by: Charles Banas | last post by:
I'm not sure if this is the right place to ask about this, but I've seen several posts in the past regarding Akima's Bivariate Interpolations routines, and i'm wondering if someone can give me some...
3
by: Jonas Ernst | last post by:
Hi, Can somebody give me some hints how to do a line interpolation without using floating point arithemtics? The function shall do a linear interpolation between 2 points (line interp?) and...
37
by: pochartrand | last post by:
Hello, Is there a way to manipulate or at least read the pseudo-class of an element ? I know the style attribute can be accessed and gives the CSS properties for a particular element....
3
by: dshan | last post by:
Hi all, I can't find an answer to my quesiton anywhere. Given a drop-down list with USA states and other text fields I pass this information for further processing via PHP. If any of the...
9
by: lev | last post by:
Attempting to use javascript's regular expression methods to match a particular lab number and building which would then be copied to a pair of textfields, I found that general matching characters...
5
by: August Karlstrom | last post by:
Hi, Does anyone know the correct syntax to interpolate a class variable, $x say, inside a string? I tried "{self::$x}" but it produces the string {self::x}
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.