Can/should one add expando properties to host-supplied objects?

Y

ytrewq

Should dynamic ("expando") properties be restricted to native and
user-defined objects? Or should host objects - such as references to
the browser or a plug-in or to the document and its elements - also
allow them?

Adding (and removing) object properties dynamically is an acceptable
and common practice in JavaScript, and greatly adds to the power and
character of the language. Essentially, an object in JavaScript can be
considered to be a collection of name-value pairs that define its
properties (including methods, as function-valued properties), and one
is usually free to add to this properties list at will.

Well, that is certainly the case for native (built-in) objects, such as
those of type Object, Number, String, Array, Date, etc; also for any
objects created from user-defined (programmer-defined) constructor
functions.

But I have never been certain if it was advisable, or even "legal", to
add properties to objects created by the host, such as the document
object or an HTML element or an XML node.

(Trivial example: document.myNewProp = 1234; )

Obviously, the actual host-supplied object - presumably, an instance of
a class written in C++ or Java or a similar statically, strongly typed,
compiled language - cannot have new properties, such as myNewProp,
added at run-time. But I have always understood - correct me if I am
wrong - that the JavaScript interpreter would automatically create a
second object, on the JavaScript side of the DOM interface, as a proxy.
That is, a JavaScript-language proxy object would map onto the
host-language class-based object. The new property ("myNewProp") would
be added only to that proxy object, as just another name/value pair,
and not to the host object, which would know nothing of the addition.

Well that is the mental image I had of the process behind the scenes.

Adding expando properties does seems fairly common practice, and I have
succeeded with this practice until now, but that does not prove much;
perhaps the host programs and/or JavaScript interpreters/engines have
just been too lax and accomodating.

The reason for this message is that my luck has finally run out, with
the Batik/Squiggle SVG viewer (which I believe runs the Mozilla Rhino
JavaScript engine, written in Java) and I am seeking a resolution of
the problem.

I had been developing some interactive, scripted SVG applications, and
had added extra data, in the form of expando properties, to some SVG
element objects (<rect> elements, for example), as a convenient way of
attaching metadata directly to them, rather than having to keep track
of separate JavaScript arrays or collections of data. This approach
worked in ASV3 and ASV6 (Adobe SVG viewer plug-ins, versions 3 and 6)
within both IE6 and Mozilla Firefox 1.0. (running on a Windows 2000 OS
PC) But not in Batik 1.5.

I have drastically simplified the example SVG file to the following
rather trivial test-case:
======================================================================================================

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">

<svg xmlns="http://www.w3.org/2000/svg" version="1" width="100%"
height="100%" onload="init(evt)">

<script><![CDATA[
function init(evt) {
var doc = evt.target.ownerDocument;
var rct = doc.getElementById("rct1");
rct.newProp = 1234;
alert("rct.newProp=" + rct.newProp);
}
]]></script>

<rect id="rct1" width="200" height="100" style="fill:red" />

</svg>

======================================================================================================

This works as intended in the Adobe plug-in in IE6 and in Mozilla. But
in Batik/Squiggle I got this error message:

org.mozilla.javascript.EvaluatorException: Java class
"org.apache.batik.dom.svg.SVGOMRectElement"
has no public instance field or method named "newProp".


This suggests that the JavaScript interpreter is trying to add -
without any proper error trapping - the "newProp" property to the host
object (of Java class SVGOMRectElement, which implements the SVG DOM
SVGRectElement interface), instead of to a proxy object on the
JavaScript side of the SVGRectElement interface.

Is it reasonable to regard this as a bug, or unwarranted restriction,
on the part of Batik? Or is Batik merely holding firm to a standard
that states one should not try to add properties to script references
to host-created objects?

Although this example features an XML/SVG document, I feel that this
issue is one that applies to JavaScript in general, as JavaScript is
always used in a context of some sort (web browser, SVG viewer or
plugin, HTML or XML DOM, and so on) which exposes its own objects, at
least indirectly, to the scripting language.
 
M

Martin Honnen

ytrewq wrote:

But I have never been certain if it was advisable, or even "legal", to
add properties to objects created by the host, such as the document
object or an HTML element or an XML node.

(Trivial example: document.myNewProp = 1234; )

Let's look into the ECMAScript specification (Standard ECMA-262 edition
3) to try to answer that:

Section 4 gives an overview of the types, it defines the Object type in
4.3.3 and then goes on to distinguish Native Objects (4.3.6), Built-in
Objects (4.3.7), and Host Objects (4.3.8).
Object is defined as follows: "An object is a member of the type Object.
It is an unordered collection of properties each of which
contains a primitive value, object, or function. A function stored in a
property of an object is called a
method."
Host Object is defined as follows: "Host Object
A host object is any object supplied by the host environment to complete
the execution environment of
ECMAScript. Any object that is not native is a host object."

So in scripting of HTML documents in browsers the document object for
instance is an host object.

Now to the section that deals with objects and their properties in
detail, it is section 8.6 The Object Type. Section 8.6.2 Internal
Properties and Methods includes the formal definition of read (get) or
write (put) access to a property. It has a paragraph that clearly says:
"The following table summarises the internal properties used by this
specification. The description
indicates their behaviour for native ECMAScript objects. Host objects
may implement these internal
methods with any implementation-dependent behaviour, or it may be that a
host object implements only
some internal methods and not others."

On the other hand the formal methods
[[Get]] (PropertyName) Returns the value of the property.
[[Put]] (PropertyName, Value) Sets the specified property to Value.
are listed and it then says
"Every object (including host objects) must implement the
[[Prototype]] and [[Class]] properties and the
[[Get]], [[Put]], [[CanPut]], [[HasProperty]], [[Delete]], and
[[DefaultValue]] methods."
but goes on to explain
"For native objects the [[Get]], [[Put]], [[CanPut]],
[[HasProperty]], [[Delete]] and [[DefaultValue]]
methods behave as described in described in 8.6.2.1, 8.6.2.2, 8.6.2.3,
8.6.2.4, 8.6.2.5 and 8.6.2.6,"
and "Host objects may implement these methods in any manner unless
specified otherwise;"

Thus looking at that an implementation is not required to have [[Put]]
implemented on host objects the way it usually works on native objects
where you can create a new property and set its value with
object.propertyName = expression
an host object could throw an exception on such attempts.

This is for instance the case with JScript on Windows when you create
and MSXML xmlDocument e.g.

var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
try {
xmlDocument.myNewProp = 1234;
}
catch (e) {
alert(e.message);
}

and you get an error alike "The object doesn't support this property or
method".

On the other hand it is of course desirable to be able to add properties
to host objects and usually in browser when scripting HTML this works.
As for Batik and Rhino I can't tell whether it is because of the way
Rhino principally sets up Java host objects or whether the Batik
implementors have for whatever reasons (maybe as they use some metha
scripting framework where JavaScript with Rhino is only one option)
choosen to use Rhino that way in Batik. I would guess that you are more
likely to find an answer on that in a Batik group or developer mailing list.
 
M

Martin Honnen

Martin Honnen wrote:

On the other hand it is of course desirable to be able to add properties
to host objects and usually in browser when scripting HTML this works.
As for Batik and Rhino I can't tell whether it is because of the way
Rhino principally sets up Java host objects

I have had a look at Rhino as documented on www.mozilla.org and I think
if you really set up a Java class as a JavaScript host object as
documented here
<http://www.mozilla.org/rhino/tutorial.html#JavaScriptHostObjects>
then it is possible to add properties as you like when scripting the
object with JavaScript, for instance I have compiled the simple Java
class Counter and then loaded it into the Rhino shell, created a Counter
object and them added all sorts of properties with JavaScript.
Thus if the objects exposed to script in the Batik viewer do not take
properties then it is likely that they are not set up as host objects
but are simply Java objects directly exposed to JavaScript as Rhino allows.
 
Y

ytrewq

Thank you, Martin, for these replies and for the research you have
carried out into Rhino.

Cheers!
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top