Odd behavior involving function.apply()

Discussion in 'Javascript' started by Jeff Stewart, Jul 19, 2006.

  1. Jeff Stewart

    Jeff Stewart Guest

    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.
    Jeff Stewart, Jul 19, 2006
    #1
    1. Advertising

  2. Jeff Stewart

    Jeremy Guest

    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
    Jeremy, Jul 19, 2006
    #2
    1. Advertising

  3. Jeff Stewart

    Jeff Stewart Guest

    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
    Jeff Stewart, Jul 19, 2006
    #3
  4. 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.
    Richard Cornford, Jul 19, 2006
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stefan Siegl
    Replies:
    1
    Views:
    962
    Marrow
    Jul 18, 2003
  2. Michael Speer

    Odd behavior with odd code

    Michael Speer, Feb 16, 2007, in forum: C Programming
    Replies:
    33
    Views:
    1,092
    Richard Heathfield
    Feb 18, 2007
  3. B. Chernick
    Replies:
    1
    Views:
    333
    B. Chernick
    Dec 12, 2007
  4. , India
    Replies:
    2
    Views:
    416
    Robert Fendt
    Apr 18, 2010
  5. Replies:
    5
    Views:
    165
    Öö Tiib
    Jun 15, 2013
Loading...

Share This Page