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

I'm working on a JavaScript project, and was just wondering why an object instance doesn't inherit the defineProperty() and other methods, rather than having to call the superclass (superobject?) Object method.
I've looked at the MDN docs, and there are in fact "non-standard" property methods.
But those are deprecated. Why would the move be to the Object methods?
It seems to me that something like instance.defineProperty(...) is better than Object.defineProperty(instance, ...). I would say the same about some of the other Object methods as well.

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);
}
});

It's done like that to avoid collisions - remember, every method on Object.prototype is a method in every single user-defined object, too.
Imagine an object where you'd want a custom method defineProperty - that would completely break things when Object.defineProperty was on its prototype instead.

Interesting. The only reason I came up with so far is that people like to rewrite the prototypes and having this method "hidden" like this might help you avoid some bugs. Especially because of the good method name since that is more likely to get rewritten than, for example, __defineGetter__.
It seems that a lot of features depend on this functionality (link), so it makes sense to make it more global and secure in this context.

Related

Prototypical OO: extending an object that is not "class-like"

Prototypical OO talks about getting rid of the class-instance distinction and having only objects. Objects inherit from other object.
However, all examples that I've seen end up having "class-like" objects and "instance-like" objects. The former have a set of methods and maybe constants and are typically immutable once they're built. The latter contain actual instance data, delegate method calls to "class-like" ones and can be either mutable or immutable as needed.
Are there any good examples where having something which behaves like both of them is beneficial to the application architecture? Can something be though of as an instance with, let's say, mutable fields, and, at the same time, a prototype for a number of other objects? Not a contrived example, but something that looks like it makes a real system easier to understand, maintain, etc?
class Example { }
console.log(Example.toString())
It works as classes are Function instances...

What is the advantage of property attributes "feature" in ECMAScript-5?

I want to know more about usage of property attributes described here:
http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.1
I can imagine usecases of these attributes, but they are very rare.
In addition writable, enumerable and configurable properties are set to false by default, but mostly I want to have these values true, so I have to set them. Why are they false by default?
Make object and set its attributes was very basic thing for me. Now there is property descriptor, which I could describe like artificial, unnatural, complicated or uncomfortable. Maybe I just missed something very essential.
So my questions are: What is main purpose of property attributes. How can we use them?
Can I avoid using property descriptor? For example with some good pattern that will set attributes for me? For example if I use Object.create with second param "Properties", it forces me to use property descriptor. So should I avoid to use this?
"...mostly I want to have these values true, so I have to set them."
Only if you have a need for them. If you don't, then just use the typical object literal syntax, or the assignment operator for new properties.
"Why are they false by default?"
I would imagine it's because there's already a syntax available that defaults them to true.
"Make object and set its attributes was very basic thing for me. Now there is property descriptor..."
Nothing has changed. It's just as basic as it was before. There are simply more tools at your disposal if you need them.
"...which I could describe like artificial, unnatural, complicated or uncomfortable."
The syntax is perhaps a little cumbersome, but if you don't like it, don't use it. If you need to set the property descriptors to something other than true, then I would think you'd be glad to have the new capabilities, irrespective of its syntax.
Also, there's likely property descriptor definition being added to object literal syntax in ECMAScript 6.
"So my questions are: What is main purpose of property attributes. How can we use them?"
That should be self-explanatory. They're for manually configuring the configurable, writeable, and enumerable settings of properties on an object. If you ever come across a situation where you need one of those settings, you'll use them.
"Can I avoid using property descriptor?"
Of course. Again, nothing has changed. They're there if you need them. If you don't, then ignore them.
"For example with some good pattern that will set attributes for me?"
Not sure what you mean, but if you want different defaults, just use a helper function, like:
function addWriteable(obj, prop, value) {
return Object.defineProperty(obj, prop, {
writeable: true
});
}
The default for writeable is false only if
If the value of an attribute is not explicitly specified by this specification for a named property
For properties you define by hand it will be true for example. The thing you should be aware of that there is a huge difference between ecmascript itself without any specification on top of it and the javascript/jscript dialects.
Either way, in general you should never do anything with these attribute properties, except if you're considering making a framework or anything along those lines. For example, prototype.js could use it to set Enumerable to false and I used it myself to redefine the Get to allow a bit of an exotic syntax which was easier for developers to use (similar to a different native syntax), but whilst doing normal stuff you don't need it.

Add a JavaScript getter/setter to a native unconfigurable property

I am using special getter/setters to intercept changes made to properties of an object, and it currently works great for any normal user-defined properties. However, I would love if I could employ the same idea to built-in properties like HTMLInputElement.value or Array.length, but these are unfortunately defined as unconfigurable and thus I get an error when attempting to redefine them using a getter/setter.
I'm just wondering if there's any kind of (reliable) hack that I can do to force these to be redefined without breaking their internal operation.
If not, I'll probably be forced to define alternate properties for all of these that simply map to the native properties and use them instead, but that's just so not ideal.
Work with JavaScript 1.8.1 on later : Defining getters and setters
that is not in any way a good practise, but if you really need to, those functions are defined on the prototype level so:
Array.prototype.length = (function(){})();
Ok, i think even this approach doesn't work with some functions, they must be protected

JavaScript best practices, extending natives with *statics*

Some people will tell you that adding prototypes to JavaScript natives is evil. For example:
String.prototype.format = function(format, replacements) {
...
};
Now, for those that agree with that (if you don't, do not reply with answer—your opinion is N/A; this is not a discussion about prototypes), is adding static methods to natives equally as evil? (Hitherto and henceforth, "static" meaning simply a method whose context isn't an instance.)
For example, given that creating a String.prototype.format is evil, is adding it as a static an acceptable practice?
String.format = function(format, replacements) {
...
};
How is extending a native with a static method any different, concerning best-practices, than extending a native with a prototype? Either you're against extending natives in any way, or you're not—is there anyone in the camp that static extensions are acceptable while prototypal are not?
Ask yourself why extending natives is evil.
Common reasons are
Not future-proof, what if the standards say "There shall be a String.format"
Not past-proof, adding enumerable properties to prototypes will break bad code.
may lead to confusion as to what's common and what's standard
may break bad-code (duck-typing, looks like a duck, quaks like a --- throws exception :()
It's simply a matter of weighing up how much you value those reasons. I only care about #1 (future-proofing).
Adding a static method to a native Constructor will not likely have an unexpected impact on someone else's code or the time it takes to construct objects using said Constructor.
However, when you add a prototype method to a native Constrcutor, every instance (even the ones created to do operations like "test".indexOf("t")) will have the additional overhead of your method. Iterating over object properties or testing capabilities (since we often can't judge an object by its type) gets more difficult.
Let's say you add String.prototype.forEach in your code. That will leak into every module. Now when some other code tests for the forEach method (thinking it's an array in a modern browser), they'll get a string instead--evil.

Extending Object.prototype JavaScript

I am not asking if this is okay:
Object.prototype.method = function(){};
This is deemed evil by pretty much everyone, considering it messes up for(var i in obj).
The Real Question
Ignoring
Incompetent browsers(browsers that don't support Object.defineProperty)
Potential for property collision or overriding
Assuming you have some incredibly useful method, is this considered wrong/unethical?
Object.defineProperty(Object.prototype, 'methodOnSteriods',{
value: function(){ /* Makes breakfast, solves world peace, takes out trash */ },
writable: true,
configurable: true,
enumerable: false
});
If you believe the above is unethical, why would they even implement the feature in the first place?
UPDATE from 2021
Despite this being the accepted answer, 10 years of experience has taught me this isn't the best idea. Pretty much anything you can do to avoid polluting the global scope is a very very good thing.
Original answer below, for posterity, and because stack overflow will not let me delete an accepted answer.
Original answer from 2011
I think it's fine if it works in your target environment.
Also I think prototype extension paranoia is overblown. As long as you use hasOwnProperty() like a good developer that it's all fine. Worst case, you overload that property elsewhere and lose the method. But that's your own fault if you do that.
I'd say this is almost as evil as before. The biggest problem, still the same as before, is that Object.prototype is global. While your method might currently be solving world peace, it might have overwriten someone else's method (that was guaranteeing galactic peace) or may be overwritten in the future by some library you have no control over (therefore plunging the world into chaos again)
New versions of Javascript have lots of features related to properties, such as definig a property to be enumerable/not enumerable, having getters and setters... Object.defineProperty existis to give control over this.
From Mozilla Docs:
This method allows precise addition to or modification of a property
on an object. Normal property addition through assignment creates
properties which show up during property enumeration (for...in loop),
whose values may be changed, and which may be deleted. This method
allows these extra details to be changed from their defaults.
This new function is basically required to support the new features and you are supposed to use it on your own stuff. Being able to modify Object.prototype is just a side effect of it also being a "normal" object and is just as evil as before.
Well in "JavaScript: the good parts", there is a similar function, i think that is very usefull to improve javascript base objects (like String, Date, etc..), but just for that.
// Add a method conditionally. from "JavaScript: the good parts"
Function.prototype.method = function (name, func) {
if (!this.prototype[name]) {
this.prototype[name] = func;
}
}
.hasOwnProperty() will exclude iteration through inherited properties, which I personally find is often more annoying than helpful. It largely defeats the usefulness of Object.create()—which is ironic since the same guy who convinced everyone to do .hasOwnProperty() also promoted Object.create().
Object.prototype should not be extended, for the reasons listed here. If you really do want to extend it, then make the extensions non-iterable.
I realize this flies in the face of all of the published best-practices, but we really should stop “mandating” .hasOwnProperty() on object key iterations and embrace the usefulness of direct object-to-object inheritance.
The short answer is Yes, you should do it.
Before doing it, there are several precautions need to take:
1. using hasOwnProperty when iterating object, but this isn't really a precautions, when iterating object, I am already using hasOwnProperty anyway.
2. check if the name in Object.prototype.name has existed, this is very safe to avoid name collision.
3. take advantage of Object.defineProperty(), just add extra safeguard layer.
As you can see, it's not very complicated.
Now comes the advantages once you have taken care of the risks/disadvantages:
1. method chaining, this just makes code more readable, terse, and making coding more enjoyable. In turn makes you happier, and your life easier.
2. solves the browser compatibility issue, you are doing polyfill anyway.
P.S.:
Don't do it when working with a large team for sure.

Categories

Resources