Invisible JavaScript functions
If you’re writing document-level JavaScript code in a PDF file, any variables you declare or assign to outside a function are created in the global object, which is the PDF document.
Suppose we have a PDF with this code as a document script, which creates three variables in three different ways:
If we load this PDF and examine its variables in the JavaScript console, we see that each of the three variables is defined both as a global variable and as a property of this
, the document object. That seems surprising until you consider that in Acrobat JavaScript, the document object is the global object.
myVar 11 this.myVar 11 myNoVar 22 this.myNoVar 22 myProp 33 this.myProp 33(Keyboard input is in
bold
, and we type Ctrl+Enter at the end of each line to evaluate the expression.)
When you’re writing code, you don’t want to pollute the document object’s namespace needlessly. You can wrap up your code in a function, so that variables you create with a var
statement are local to the function.
Adobe Acrobat encourages this by creating a function for you when you add a document script. If you use Acrobat’s Document JavaScripts dialog to add a script called DocScript
, you’ll get an empty function to fill in:
doc
instead of this
. We didn’t have to do that, but I like to be able to use doc.whatever
instead of this.whatever
for document properties.
If we look at these variables in the console window, the results are different:
myVar1 ReferenceError: myVar1 is not defined 1:Console:Exec undefined this.myVar1 undefined myNoVar1 22 this.myNoVar1 22 myProp1 33 this.myProp1 33As expected,
myVar1
does not show up either in the global object or the document object; it is local to the function. myVar2
does (because we didn’t use var
), as does myProp1
(because we created it as a property of the doc object).
The difference between myVar1
and this.myVar1
is expected too. It’s an error to reference a variable name that does not exist, so myVar1
throws a ReferenceError
exception. But it’s not an error to reference a nonexistent property of an objectthe reference merely returns the undefined
value. So this.myVar1
returns undefined
without error.
But we’ve still put one name in the document object:
DocScript function DocScript(doc) { var myVar1 = 11; myNoVar1 = 22; doc.myProp1 = 33; } this.DocScript function DocScript(doc) { var myVar1 = 11; myNoVar1 = 22; doc.myProp1 = 33; }
To avoid even this bit of namespace clutter, we can define an anonymous function and call it on the spot:
The console results for myVar2
, etc. are the same as the previous example with the named function, so I won’t repeat them. But unlike the named function, we haven’t added any symbols at all to the document or global object.
Why the extra parentheses? function(){}
is the simplest possible anonymous function, but if we try to call it using function(){}()
it’s a syntax error. However, if we wrap the entire function inside a pair of parentheses, then we can follow that with ()
to call it: (function(){})()
is legal JavaScript.
The same trick works when you want to add a nested scope inside a function. The way you would do this in C doesn’t work in JavaScript:
That code prints:
1 2 2
because there is only one variable named i
in the entire function, even though we’ve (incorrectly) tried to add an inner scope with its own variable i
.
In fact, if you load that function into ActiveState Komodo, it puts a green squiggly line under the inner var i = 2;
complaining “strict warning: redeclaration of var i”.
But if we use a nested anonymous function:
it prints:
1 2 1
which indicates that the nested function introduced a new scope.
Hi Michael,
I’m working on a C#.NET desktop application which creates pdf files. The files are generated by populating pre-existing pdf templates. These templates contain document level javascript. My question, how do I invoke the embedded document level javascript from my C#.NET desktop application? I’ve been studying the Adobe SDK, etc but haven’t had any luck with the actual implementation. Any advice would be much appreciated, thanks!