Is it possible to emulate non-enumerable properties?

ES5 has a enumerable flag. Example

Example
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
 , pd = getOwnPropertyDescriptor(Object.prototype, "toString");

assert(pd.enumerable === false, "enumerability has the wrong value");
Partial implementation

Partial implementation is do-able by having Object.keys and Object.getOwnPropertyNames filter out new non-enumerable properties using the shimmed Object.defineProperty.

Introduction

This allows for properties to be non enumerable. This clearly means that Example

for (var key in {}) {
    assert(key !== "toString", "I should never print");
}

This allows us to add properties to say Object.prototype (Example)

Object.defineProperty(Object.prototype, "toUpperCaseString", {
    value: function toUpperCaseString() {
        return this.toString().toUpperCase();
    },
    enumerable: false
});

for (var key in {}) {
    assert(key !== "toUpperCaseString", "I should never print");
}

console.log(({}).toUpperCaseString()); // "[OBJECT OBJECT]"
Question

How can we emulate this in non-ES5 compliant browsers?

Browser compat table

In this case we care about potentially solving this for

  • IE < 9 (IE8 only works on DOM objects)
  • Firefox 3.6
  • Safari 4
  • Opera 11.5 (Opera 11.6 solves this).

The ES5-shim does not have a solution for this.

The ES5 shim has a solution for most ES5 features that will break your code if it doesn't work.

Is there any black magic that can be done with propiotory IE only APIs? Maybe with VBScript?

Answers


You can do it via code-rewriting. Rewrite every use of for (p in o) body to

for (p in o) {
  if (!(/^__notenum_/.test(p) || o['__notenum_' + p])) {
    body
  } 
}

and then you can mark properties not enumerable by defining a __notenum_... property. To be compatible you would have to tweak the above to make sure that __notenum_propname is defined at the same prototype level as propname, and if you use them, overwrite eval and new Function to rewrite.

That's basically what ES5/3 does.


Partial.js by Jake Verbaten is the answer to it.

The partial.js is as follows

/* partial non-enumerable property implementation

  Adds a flag to a weakmap saying on obj foo property bar is not enumerable.

  Then checks that flag in Object.keys emulation.
*/

// pd.Name :- https://github.com/Raynos/pd#pd.Name
var enumerables = pd.Name();

Object.defineProperty = function (obj, name, prop) {
    if (prop.enumerable === false) {
         enumerables(obj)[name] = true;
    }
    ...
};

Object.keys = function (obj) {
    var enumerabilityHash = enumerables(obj), keys = [];
    for (var k in obj) {
        if (obj.hasOwnProperty(k) && !enumerabilityHash[k]) {
             keys.push(k);
        }
    }
    return keys;
};

Object.getOwnPropertyNames = function (obj) {
    var keys = [];
    for (var k in obj) { 
        if (obj.hasOwnProperty(k)) {
             keys.push(k);
        }
    }
};

I hope this helps the guys searching for this fix.


If you do care a lot about IE8/IE7 then you can do

for (p in o) {
   if (o.hasOwnProperty(p)) { body } 
}

There is no real "hack" alternative but this could be a work-around for simple cases

The accepted answer doesn't really work for literals i.e. strings "", numbers 3, or booleans true


Need Your Help

How to display scrollbar in UITableView

iphone uitableview scrollbar

I want to display some kind of indication to guide user to scroll.

Does Hibernate always need a setter when there is a getter?

java hibernate getter-setter

We have some Hibernate getter methods annotated with both @Column and @Basic.