By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,648 Members | 1,558 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,648 IT Pros & Developers. It's quick & easy.

Odd behavior involving function.apply()

P: n/a
I've been working with the JavaScript Shell in Firefox on a
mad-scientist problem I've had in my head. Assume a function named
'object' that is designed to create an object based on a prototype
object -- the semantic is that the returned object prototypally
inherits from the argument 'o'.

function object(initializer, o) {
if (!o) o = Object;
function f() {}
f.prototype = o;
obj = new f();
obj.__progenitor = o;

if (initializer) {
if ((typeof(initializer)).toLowerCase() != "function") throw
"Expected initializer to be of type function, got type " +
typeof(initializer);
initializer.apply(obj);
}

return obj;
}

Now assume these uses of the object() function:

SimplePattern = object();

Prototype = object(
function() {
this.prototypeValue = "Yo";
this.message = function(message) {alert(message);}
},
Object
);

Thing = object(
function() {
var secret = 42;
var _outer = this;

_outer.GiveUpSecret = function() { return secret; }
},
Prototype
);

These all produce the results I would expect. Typical prototypal
inheritance.

But if I alter the Thing definition's initializer to include a member
that should inherit from Prototype,

Thing = object(
function() {
var secret = 42;
var _outer = this;

_outer.GiveUpSecret = function() { return secret; }
_outer.subObject = object(
function initializer() {
var _inner = this;
_inner.subObjectProp = 73;
},
Prototype
);
},
Prototype
);

Thing all of a sudden is -missing- its GiveUpSecret() function, has no
subObject member, and reports its prototypeValue as "Yo".

Why doesn't this work more intuitively?

--
Jeff S.

Jul 18 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Jeff Stewart wrote:
<snipped long, complicated test case>

Why doesn't this work more intuitively?
The best kind of irony is unintentional irony. That made me laugh out
loud :-)

As for your problem - your code looks like a scope quagmire to me.
Shouldn't you be assigning properties to your object rather than
creating them as local variables (as with "secret")? I don't fully
understand what you're trying to do - are you trying to create an
*object* that inherits from Prototype, or a new *type* that inherits
from Prototype?

Can you explain what you're trying to do? Maybe there's an analogous
pattern in a different language that you're trying to emulate? Whatever
it is, there is probably a simpler way.

Jeremy
Jul 19 '06 #2

P: n/a
The 'secret' is designed to illustrate that a hidden member could be
introduced into the created object using this pattern. It's based on
what I read on Crockford.com.

As for the intent, considering JavaScript really doesn't have "types",
I'm trying to create a new -object-. I'm obsessed lately with the idea
that JavaScript 1) was never designed to support classes (yet everyone
tries to force it to), 2) supports -prototypal- inheritance instead of
class-based inheritance, and 3) prototypes are -not- classes.

So the object() function is supposed to create either 1) objects with
an "instance" semantic attached to them, or 2) patterns -- prototypes
-- upon which other objects are based. But it should be composable --
again, the philosophy I'm adopting is that objects inherit from
prototypes, not classes/types. And, thusly, an object/instance created
from a prototype should be capable of acting as a prototype itself.

object() should be the root of this functionality: any source object,
by virtue of JavaScript, can be used as a prototype to create any other
object which can be said to "inherit" from the source object. I'm
trying to get back to basics amidst all the half-baked classical
inheritance implementations that do many things well but not the whole
thing with excellence. But though I'm getting back to basics, I still
want to try and introduce things like information hiding into the mix.

object() is a very hairy mutation of the function Crockford discusses
here: http://javascript.crockford.com/prototypal.html. I wasn't
satisfied with that method because it didn't support a more intuititve
initialization mechanism.

I had something I liked until I tried nested creation. In this
particular problem, I can't understand how the addition of one
property, subObject can so dramatically alter its owner object. I
thought I'd isolated all my execution contexts properly by latching
onto 'this' in all the right places using local variables, but somehow
the -nested- call to object() ended up modifying the object that
-owned- the call. How was that boundary violated?

As for it being a scope quagmire, well, in my defense, it -is-
JavaScript. Scope stopped being an easy concept when I was introduced
to the wild world of closures. :)

--
Jeff S.
Jeremy wrote:
Jeff Stewart wrote:
<snipped long, complicated test case>

Why doesn't this work more intuitively?

The best kind of irony is unintentional irony. That made me laugh out
loud :-)

As for your problem - your code looks like a scope quagmire to me.
Shouldn't you be assigning properties to your object rather than
creating them as local variables (as with "secret")? I don't fully
understand what you're trying to do - are you trying to create an
*object* that inherits from Prototype, or a new *type* that inherits
from Prototype?

Can you explain what you're trying to do? Maybe there's an analogous
pattern in a different language that you're trying to emulate? Whatever
it is, there is probably a simpler way.

Jeremy
Jul 19 '06 #3

P: n/a
Jeff Stewart wrote:
I've been working with the JavaScript Shell in Firefox on
a mad-scientist problem I've had in my head. Assume a
function named 'object' that is designed to create an
object based on a prototype object -- the semantic is that
the returned object prototypally inherits from the argument
'o'.

function object(initializer, o) {
if (!o) o = Object;
function f() {}
f.prototype = o;
obj = new f();
The variable - obj - has not been declared in this code and so will act
as a global variable. This is the root of your problem as when this
function is called recursively in your example the inner recursion
re-sets the global - obj - variable to the object it is creating during
the - apply - call, and so when that returns and the outer call then
returns - obj - it is the object created during the inner recursion that
is returned and assigned to the - Thing - variable.
obj.__progenitor = o;

if (initializer) {
if ((typeof(initializer)).toLowerCase() != "function") throw
The - typeof - operator is clearly specified as returning the string
'function' when its operand is a javascript function. There is no need
to convert that string to lowercase for the comparison, and it is
probably dangerous to try to call apply on anything but a javascript
function so if - typeof - returned a mixed or uppercase version of
'function' then it would be a bad idea to then go on and call an apply
method on the object in question.
"Expected initializer to be of type function, got type " +
typeof(initializer);
initializer.apply(obj);
}

return obj;
}

Now assume these uses of the object() function:

SimplePattern = object();

Prototype = object(
It cannot be a good idea to use the Identifier - Prototype - as if the
environment has/exposes an internal constructor for creating prototypes
that will likely be its name.

With the - obj - declared as a local variable, an actual object (- new
Object -) being passes into the function in place of - Object -, and
the - Prototype - Identifier changed to - PrototypeX -, the code
produces the results you seem to expect from it.

<snip>
Why doesn't this work more intuitively?
It is ridiculously convoluted, why do you expect it to be intuitive?

Richard.
Jul 19 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.