Properties determine the state of an object in JavaScript. This blog post examines in detail how they work.
    var obj = {
        prop: 123
    };
You can get (read) a property:
    console.log(obj.prop); // 123
    console.log(obj["prop"]); // 123
And you can set (write) a property:
    obj.prop = "abc";
    obj["prop"] = "abc";
    var obj = {
        get prop() {
            return "Getter";
        },
        set prop(value) {
            console.log("Setter: "+value);
        }
    }
Let’s interact with obj:
    > obj.prop
    'Getter'
    > obj.prop = 123;
    Setter: 123
The following attributes are specific to named data properties:
| Attribute key | Default value | 
| [[Value]] | undefined | 
| [[Get]] | undefined | 
| [[Set]] | undefined | 
| [[Writable]] | false | 
| [[Enumerable]] | false | 
| [[Configurable]] | false | 
These defaults are especially important for property descriptors (see below).
    {
        value: 123,
        writable: false,
        enumerable: true,
        configurable: false
    }
You can achieve the same goal, immutability, via accessors. Then the descriptor looks as follows:
    {
        get: function () { return 123 },
        enumerable: true,
        configurable: false
    }
    var obj = Object.defineProperty({}, "foo", {
        value: 123,
        enumerable: true
        // writable and configurable via defaults
    });
        var obj = Object.defineProperties({}, {
        foo: { value: 123, enumerable: true },
        bar: { value: "abc", enumerable: true }
    });
        var obj = Object.create(Object.prototype, {
        foo: { value: 123, enumerable: true },
        bar: { value: "abc", enumerable: true }
    });
        > Object.getOwnPropertyDescriptor(Object.prototype, "toString")
    { value: [Function: toString],
      writable: true,
      enumerable: false,
      configurable: true }
    > Object.getOwnPropertyDescriptor({}, "toString")
    undefined
        var proto = Object.defineProperties({}, {
        foo: { value: 1, enumerable: true },
        bar: { value: 2, enumerable: false }
    });
    var obj = Object.create(proto, {
        baz: { value: 1, enumerable: true },
        qux: { value: 2, enumerable: false }
    });
Note that objects (including proto) normally have at least the prototype Object.prototype [2]:
    > Object.getPrototypeOf({}) === Object.prototype
    true
Object.prototype is where standard methods such as toString and hasOwnProperty are defined.
The for-in loop iterates over the names of all enumerable properties, including inherited ones (note that none of the non-enumerable properties of Object.prototype show up):
    > for (var x in obj) console.log(x);
    baz
    foo
Object.keys() returns the names of all own (non-inherited) enumerable properties:
    > Object.keys(obj)
    [ 'baz' ]
If you want the names of all own properties, you need to use Object.getOwnPropertyNames() (see example below).
    > "toString" in obj
    true
    > obj.toString
    [Function: toString]
Other read operations only work with own properties:
    > Object.getOwnPropertyNames(obj)
    [ 'baz', 'qux' ]
    > obj.hasOwnProperty("qux")
    true
    > obj.hasOwnProperty("toString")
    false
    > Object.getOwnPropertyDescriptor(obj, "qux")
    { value: 2,
      writable: false,
      enumerable: false,
      configurable: false }
    > Object.getOwnPropertyDescriptor(obj, "toString")
    undefined
Creating, deleting and defining properties only affects the first object in a prototype chain:
    obj.propName = value
    obj["propName"] = value
    delete obj.propName
    delete obj["propName"]
    Object.defineProperty(obj, propName, desc)
    Object.defineProperties(obj, descObj)
    > Object.keys([])
    []
    > Object.getOwnPropertyNames([])
    [ 'length' ]
    > Object.keys(['a'])
    [ '0' ]
That especially holds for the methods in prototype objects:
    > Object.keys(Object.prototype)
    []
    > Object.getOwnPropertyNames(Object.prototype)
    [ hasOwnProperty',
      'valueOf',
      'constructor',
      'toLocaleString',
      'isPrototypeOf',
      'propertyIsEnumerable',
      'toString' ]
Thus, for your code, you should ignore enumerability. You normally shouldn’t add properties to built-in prototypes and objects, but if you do, you should make them non-enumerable to avoid breaking code.
As we have seen, non-enumerability mostly benefits for-in and ensures that legacy code using it won’t break. The non-enumerable properties create the illusion that for-in only iterates over the user-created own properties of an object. In your code, you should avoid for-in if you can [3].
If you use objects as maps from strings to values, you should only work with own properties and ignore enumerability. But there are more pitfalls for this use case [4].
Further reading on 2ality: