read


read
or learn more

A JavaScript Puzzler

Jun 1, 2011

[sourcecode lang=”javascript” gist=”1002886″]var M = function() { this.m = function() { return 42 } };

var inst = new M();

inst.f = function() { return 42 };

// How to tell that f is a function in a field and // m is a method in an arbitrary object? // // example:

is_method(inst.f); //=> false

is_method(inst.m); //=> true

// Is it possible to write is_method? [/sourcecode]

7 Comments, Comment or Ping

  1. I don’t know of a way.

    Also, assigning functions to the object via “this” in the constructor will generate new, unique, functions for each instance.

    Consider

    function N() { this.x = function() {}} N.prototype.y = function() {} new N().x == new N().x false new N().y == new N().y true

    Is using prototype an option?

    var M = function(){} M.prototype.m = function() { return 42 }

    var inst = new M() inst.f = function() { return 42 }

    function is_method(o,name){ var p = o.constructor.prototype return p[name] && p[name] === o[name] }

    is_method(inst,”f”) is_method(inst,”m”) // true

  2. adrusi

    I don’t thinks so, but if you redesigned the syntax to is_method(inst, "f") it should be, by comparing the constructor’s prototype with the actual object. Something along the lines of:

    var M = function() { this.m = function() { return 42 } };
    var inst = new M();
    inst.f = function() { return 42 };
    
    var is_method = function(obj, prop) {
      return (obj[prop] === obj.constructor.prototype[prop] && typeof obj[prop] === "function");
    }
    is_method(inst, "f"); // => false
    is_method(inst, "m"); // => true
    

    This isn’t tested, but it should work as it is or with a few modifications.

  3. mpenet

    I don’t think it’s possible, from my understanding they are essentially the same, the only difference is at what time you assign these “methods” to instances.

    Both aren’t present M.prototype

    I am not sure what you are trying to achieve but this might help you figure it out:

    https://gist.github.com/1004051

  4. If we assume that you know what is the constructor function, then you can :

    1) take the code of the constructor by doing ctorCode = M.toString(); 2) the is_method function creates some RegExp based on the name of the method you sent and searches for that string in the constructor (by searching for ‘this’ followed by zero or more spaces then looking for dot (note that . means anything in RegExp) then again zero or more spaces then the name of the method and then again zero or more spaces followed by = (and on and on look for ‘function’ and ‘(‘ )

    If there’s a match, then this is a method.

    Also, if you define a method also functions that came from the prototype chain, then you need to use the method hasOwnProperty. Basically, if the object has that method and hasOwnProperty returns false, then it’s from the prototype chain.

  5. The distinction between m and f is artificial. They are, for all intents and purposes, the exact same language element. In fact, they are added using exactly the same method right after each other. Just extract the “this.m = …” code outside the function (obviously changing “this” to “inst”) and you’re done.

    So there’s nothing magical about “m” vs “f”, and thus no way to tell them apart. Not sure why you would want to, either, they really are exactly the same.

  6. amac

    I think I’ve got a nice solution here:

    is_method = function(fun) {
      return (null != fun.__parent__.constructor);
    };
    

    The functions in M’s fields are associated with M’s object as their parent when inst is built; whereas anonymous functions which are not associated in the object prototype are not constructed and thus don’t have a parent constructor.

    After re-writing this explanation 4 times, this was the clearest I could articulate it — sorry.

  7. amac

    there should be two underscores to each side of the parent magic value, I’m unfamiliar with the markup here.

Reply to “A JavaScript Puzzler”