Skip to content

Instantly share code, notes, and snippets.

@WebReflection
Created August 20, 2011 08:32
Show Gist options
  • Save WebReflection/1158853 to your computer and use it in GitHub Desktop.
Save WebReflection/1158853 to your computer and use it in GitHub Desktop.

Revisions

  1. WebReflection created this gist Aug 20, 2011.
    131 changes: 131 additions & 0 deletions Object.prototype.in.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,131 @@
    (function(Object, String){

    // (C) WebReflection - Mit Style License
    // @about implementing "in" operator as generic object method

    // returns primitive value or object itself
    function toValue(obj) {
    switch (true) {
    case isInstanceOf(obj, Boolean):
    case isInstanceOf(obj, Number):
    case isInstanceOf(obj, String):
    return obj.valueOf();
    default:
    return obj;
    }
    }

    // reduce occurrences of "instanceof" for minified code
    function isInstanceOf(obj, constructor) {
    return obj instanceof constructor;
    }

    var // block of private variables

    // used to grab indeOf and toString
    // should be trashed automatically
    array = [],

    // quirk implementation, enough here
    indexOf = array.indexOf || function (value) {
    var i = this.length;
    while (i-- && this[i] !== value) {}
    return i;
    },

    // minifiers shortcuts
    proto = Object.prototype,
    toString = proto.toString,
    floor = Math.floor,
    FALSE = false,

    // make it compatible with different
    // JS implementations, Rhino too
    ARRAY = toString.call(array)
    ;

    // do not redefine if present
    "in" in proto || Object.defineProperty(proto, "in", {

    // force defaults (just in case)
    writable: FALSE,
    enumerable: FALSE,
    configurable: FALSE,

    // the "in" method
    value: function (obj) {

    var
    // reused later on
    value, key,

    // minifiers shortcut
    self = this
    ;

    // operation is both context
    // and argument dependent
    switch (typeof obj) {

    // obj is Array or generic Object
    case "object":

    // "value".in(["some", "value"]); // true
    if (toString.call(obj) === ARRAY) {
    return -1 < indexOf.call(obj, toValue(self));
    }

    // "value".in({some: "value"}); // true
    value = toValue(self);
    for (key in obj) {
    // inherited too as is for "in" operator
    if (obj[key] === value) {
    return true;
    }
    }

    return FALSE;

    //* hard to say if anything that's not object
    // should accepted as "in" argument
    // if you think so, comment out this part
    // just removing first slash of this comment

    case "string":
    // "bc".in("abcd"); // true
    if (isInstanceOf(self, String)) {
    return -1 < obj.indexOf(self);
    }

    case "number":
    // (3).in(15); // true as part of gcd
    if (isInstanceOf(self, Number)) {
    value = obj / self;
    return floor(value) === value;
    }
    //*/
    }
    return FALSE;
    }
    });

    }(Object, String));

    /* da test, add a sash to perform the test => //* rather than /*
    alert([
    0 in [3,4,5], // true, index 0 exists
    (4).in([3,4,5]), // true, array contains value 0
    (3).in(15), // true, 15 can be divided by 3
    3..in({three: 3}), // true, object has a property with value 3
    "three" in {three: 3}, // true, three as property name
    "bc".in("abcd"), // true, string "abcd" contains "bc"
    "b".in(["a","b","c"]), // true, array contains value "b"
    "b".in({a:"b"}), // true, object has no property with value "b"
    (0).in([3,4,5]), // false, array does not contain value 0
    (2).in({three: 3}), // false, object has no property with value 2
    "three".in({three: 3}), // false, object has no property with value "three"
    "b" in ["a","b","c"] // false, b is not a valid index
    ].join("\n"));
    //*/