The Trouble with ‘this’

You may be doing more typing than necessary

Programming requires a lot of repetitive typing of variable and method names
(have you noticed?), which in turn invites typos, so I like to look for ways
to cut down on needless typing (hence needless typo-chasing). At the risk of
being pelted with overripe vegetables, I’d like to take to the soapbox for a
minute to tell you about my latest recommendation for eliminating needless
keystrokes while writing JavaScript for PDF.

Very simply, stop using ‘this’ where it’s not needed. Which is practically
everywhere.

I’ve come to the reluctant conclusion that we’ve all been witless saps for
typing ‘this’ in front of Doc object properties and methods all these years.
(At least, it feels like years…) You know what I’m talking about:


var name = this.getField('name').value;

This is a typical example of the (unnecessary) use of ‘this’ as an object
specifier. We use ‘this’ on the front of Doc object methods and properties,
ostensibly, to specify the current document’s Doc object. In theory, one
could obtain a remote PDF document’s Doc object reference (by communicating
via globals) and use it to ‘scope’ methods or properties to the remote
document. But in fact, no one programs this way. And if you do, you’re going
against Adobe’s recommendations. Adobe recommends against using any Doc
object reference(s) to any remote document(s), for the simple reason that
such references can be invalidated suddenly, without warning, if a file
closes while the Doc reference is still open.

To deal with the ‘dangling Doc reference’ problem, Adobe has come up with
publish() and subscribe() methods for Acrobat 5.0 (available now,
undocumented, in 4.05).

So if you’re not supposed to use a Doc object reference other than ‘this’,
what good is ‘this’? It is no help to the JavaScript runtime engine. By
default, Acrobat’s JavaScript interpreter always tries to scope methods like
getField(), and properties like zoom and pageNum, to the current Doc object,
which is associated with the document in which the code is executing. The
use of ‘this’ as a scoping hint is therefore meaningless, unless you’re
going against Adobe’s advice on remote doc manipulations.

A New Style of Coding

You might as well get used to the fact that code referencing Doc-object
methods will work just fine without ‘this’ on the front. Use no object
specifier at all. You can just write:

   
// set page magnification to 83%:
zoom = 83;

// take the user to page 12:
pageNum = 12;

// fetch a field value:
var name = getField('field_name').value;

// give all fields a red background color:
for (var i = numFields; i; i--)
getField(getNthFieldName(i - 1)).bgColor = color.red;

Acrobat will not complain and your user will never know the difference. Your
code will be cleaner, you’ll eliminate a lot of typing (which, for me, means
fewer typos), and the JavaScript interpreter won’t barf. No men with black
sunglasses will come to your door. No certified letters will arrive. The
Thought Police will just add it to your existing rap sheet.

When I asked a JavaScript expert at Adobe why anybody should use ‘this’ as a
Doc scoping hint, given that it’s not at all necessary, the (non)answer I
got was ‘Code just seems to read better with ‘this’…’

Why ‘this’ Can Be Dangerous

I’m going to go a step further and maintain that not only does ‘this’ serve
no useful purpose whatsoever as a Doc reference in Acrobat JavaScript, it
can actually be dangerous under certain circumstances. Let me show you an
example.

Suppose you are creating a custom object, called a Circle. Your constructor
might be:

 
function Circle(r) {

this.radius = r;
this.circumference = Math.PI * 2 * r;
this.area = r * r * Math.PI;
}

To create a Circle object with a radius of 5, you would do:

 
var c = new Circle(5);

At that point, you could inspect the value of c.area (and you’d find
that it’s 78.5398163397448).

But notice one thing. Inside our constructor function, we’ve used ‘this’ to
refer to the current object. The word ‘this’, in this context, refers to the
object created by the constructor, not the Doc object.

In fact, if you try to call a Doc object method or property, such as
this.zoom or this.calculateNow(), from inside the Circle() function, your
code will fail.

To call an Acrobat method from inside the Circle constructor, you’d have to
do something like:

 
global.mydoc = this; // grab Doc object reference

function Circle(r) {

this.radius = r;
this.circumference = Math.PI * 2 * r;
this.area = r * r * Math.PI;

global.mydoc.getField('radius').value = r;
}

The only other way to get any Doc object methods or properties to work
properly in the code for Circle() is to leave off the ‘this’ specifier.

On the other hand, if you want, you can call getField() completely bare,
inside the Circle() function. (Ditto for zoom, pageNum, and all the rest.)
If you put ‘this’ on the front, Doc object calls fail.

A Different Kind of Global

In Acrobat JavaScript, there are actually two types of globals: those
attached to the Global object (whose reference is the lowercase ‘global’),
and those attached to the Doc object (whose reference is ‘this’). The scope
is different, obviously, in each case. Globals attached to ‘global’ are
visible from any open PDF document (even across sessions, if made
persistent). Variables attached to ‘this’ are visible from anywhere in the
current PDF document, but not other documents.

Let’s say you want to create a Doc-level global called myAnswers, that you
want to share between functions, but you don’t want other open PDF
documents to have access to this variable. Obviously, if you create
myAnswers as a ‘global’ property in the usual way, it becomes visible to
other PDF documents (which you don’t want). To limit the scope to just the
current document, do:

 
this.myAnswers = new Array('3.14','Sacramento','1812');

Now, any time you want to access the myAnswers array, from *any* function in
the current document (top-level, field-level, or what-have-you) you can
simply inspect this.myAnswers, or (remembering not to type ‘this’) just
myAnswers.

In fact, since ‘this’ is never necessary as a reference to the current Doc,
you can declare Doc-level globals by simply leaving off the ‘var’
declarator:

 
reply = 'Good'; // Doc-level variable

var reply = 'Bad'; // local variable

app.alert(reply); // guess which one displays?

If you’ve followed this discussion of ‘this’ this far, you can probably
guess which ‘reply’ value displays in a call to app.alert(reply). The answer
is, if the local variable is still in scope, the local ‘reply’ value (‘Bad’)
will display in the alert dialog. Otherwise, the Doc-level ‘reply’ will
display. Why? In JavaScript, as in all languages, local variables take
precedence over higher-level variables of the same name.

Having said all this, maybe it’s going too far to suggest that you should
always avoid using ‘this’ as a Doc reference. Go ahead and keep using it if
you want. (Some of us don’t like to type so much.) Just remember that inside
a constructor, ‘this’ doesn’t have the meaning you thought it did.

I call ‘this’ interesting, to say the least.

You May Also Like

About the Author: Kas Thomas

Leave a Reply