Why Is It Object.Defineproperty() Rather Than This.Defineproperty() (For Objects)

Why is it Object.defineProperty() rather than this.defineProperty() (for objects)?

It's to avoid collisions - in general, issues with objects that do not have the property with the value that you expect.

Objects in JS are often used as key-value-maps, and the keys can be arbitrary strings - for example __defineGetter__, hasOwnProperty or something less special. Now when you want to invoke such a function on an unknown object - like hasOwnProperty is often used in generic enumeration functions, where any JSON might be passed in - you can never be sure whether you got a overwritten property (that might not even be a function) or the original which you want, or whether the object inherits the property at all. To avoid this issue (or also this IE bug), you'd have to use Object.prototype.hasOwnProperty.call - that is ugly.

So, namespacing all those functions on Object is only useful, it's a cleaner API that separates the reflection methods from the object's application interface. This also helps optimisation (simplifying static analysis) and makes it easier to restrict access to the reflection API in sandboxes - at least that was the design idea.

You might be happy to have a defineProperty around in the prototype, but you can only use it safely when working with known objects. If you still want it (as you know when to use and when not), you could use

Object.defineProperty(Object.prototype, "defineProperty", {
writable: true,
enumberable: false,
value: function(prop, descr) {
return Object.defineProperty(this, prop, descr);
}
});

Object.defineproperty() vs Object.defineproperties()

As you noticed, Object.defineProperty can't handle multiple properties, it takes the target object, one property name, and one descriptor.

On the other hand, Object.defineProperties takes the target object, and another object whose every key is a property name and every value is the corresponding descriptor, which allows to define multiple properties at once.

Nothing prevents you from using Object.defineProperties even for single properties, it's just a bit more work (and maybe less readable code?) because you have to build the object which contains the properties definition.

Object.defineProperty vs vanilla property

Yes, they behave the same when

  • there is no bar property in foo (not even an inherited one), so a new one is created, or
  • there is a bar property that has the writable and configurable attributes set to true

However, if neither of those is given, the two indeed produce slightly different results.

  • defineProperty does not consider inherited properties and their descriptors
  • If the existing (possibly inherited) property is an accessor, the assignment will try to call the setter (and fail if none exists), while definePropery will overwrite the property with the data descriptor (or fail if it is an own, non-configurable one)
  • If an existing inherited property is a data property, the assignment will fail if writable is false, or create a new own property if true, like the defineProperty always does
  • If an existing own property is a data property, the assignment will fail if writable is false, or set the new value if true, while defineOwnProperty will fail iff configurable is false and overwrite the attributes otherwise.

Considering the basic scenario of usage

If by "basic usage" you mean no usage of fancy property attributes, then yes they are equivalent. Yet you should just use the simple assignments, for they are easier to read and faster to execute.

Can we fall back to vanilla in pre-ES6 applications

Notice that full support of defineProperty comes with ES5, so unless you need to consider pre-ES5 (old IE) browsers you wouldn't care at all.

when do you use Object.defineProperty()

Object.defineProperty is mainly used to set properties with specific property descriptors (e.g. read-only (constants), enumerability (to not show a property in a for (.. in ..) loop, getters, setters).

"use strict";
var myObj = {}; // Create object
// Set property (+descriptor)
Object.defineProperty(myObj, 'myprop', {
value: 5,
writable: false
});
console.log(myObj.myprop);// 5
myObj.myprop = 1; // In strict mode: TypeError: myObj.myprop is read-only

Example

This method extends the Object prototype with a property. Only the getter is defined, and the enumerability is set to false.

Object.defineProperty(Object.prototype, '__CLASS__', {
get: function() {
return Object.prototype.toString.call(this);
},
enumerable: false // = Default
});
Object.keys({}); // []
console.log([].__CLASS__); // "[object Array]"

Why does object.defineproperty not add the property to the object?

Object.assign only copies enumerable own properties.

Object.defineProperty defines non enumerable properties unless the descriptor overrides the default value (false) for enumerable.

var a ={a:1}var b={a:5,b:6}b['d']=33Object.defineProperty(b,'c',{ value:'eee', enumerable: true})var t ={}Object.assign(t,a,b)console.log(t)

Object.defineProperty or .prototype?

In two cases you are adding a new property 'startsWith' in String.prototype.

First differs from the second in this cases:

You can configure the property to be enumerable, writable and configurable.

Writable - true means that you can change its value by assigning any value. If false - you can't change the value

Object.defineProperty(String.prototype, 'startsWith', {        enumerable: false,        configurable: false,        writable: false, // Set to False        value: function(searchString, position) {            position = position || 0;            return this.lastIndexOf(searchString, position) === position;        }    });
var test = new String('Test');
test.startsWith = 'New Value';console.log(test.startsWith); // It still have the previous value in non strict mode


Related Topics



Leave a reply



Submit