Hacker News new | past | comments | ask | show | jobs | submit login

While the observations I am about to make likely will be down-voted by some/many in this forum, perhaps even be viewed as heresy, I am compelled to present them on the chance that it helps some to understand what JavaScript objects truly are.

TL;DR JavaScript "objects" are nothing more than a <a href="https://en.wikipedia.org/wiki/Hash_table">Hash map</a>.

From the article:

> Prototypes in JavaScript are “just objects,” and since they are “just objects,” we can add, remove, or modify methods of the prototype by adding, removing, or modifying the functions bound to properties of the prototype.

They are not "just objects." In fact, symantically they are nothing more than a hash map (a.k.a. hash table, dictionary)[1]. The above quote from the article clearly indicates this fact as, if we peform three simple keyword substitutions, the sentence reads thusly:

Prototypes in JavaScript are “just hash maps,” and since they are “just hash maps,” we can add, remove, or modify values of the prototype by adding, removing, or modifying the values bound to keys of the prototype.

Attempting to think of JavaScript objects in the same manner as what most mainstream "OO" languages semantically provide is simply wrong. "Prototypical inheiritance" is nothing more than a shallow copy of an associative array. By its very definition, that is _all it is_.

Now, IMHO there is nothing wrong with a hash map. There's nothing right about it either. Those sentiments imply judgement, whereas what I have said above is simply analyzing the nature of the subject. The fallacy in calling JavaScript "objects" objects lies in deceiving one's self into thinking that the same semantic guarantees OO languages provide can be done in native JavaScript. The quicker a developer accepts that JavaScript objects are simply hash maps, the quicker they can understand the semantic contract being proffered by the environment _and_ be able to work with it as best as possible.

1 - http://www.w3schools.com/js/js_object_definition.asp




As others have noted, the disclaimer detracts from your message. Just because people often say “This will be controversial, but...” does not mean that it adds to your message. It does not lower the reader’s defences against controversial ideas.

What it actually does is appeal to people who are already predisposed to heterodoxy. For example, if I begin a comment with the statement:

“This is going to bring the Men’s Rights Activist sea lions out of the woodwork, but...” What I am doing is appealing to people who are already predisposed to dislike the MRA movement and its adherents. I am absolutely not trying to appeal to people leaning that way to consider my message carefully and possibly soften their stance.

Thus, statements like this tend to be divisive and polarizing, which runs 100% counter to a culture of open minded discussion.

Far better, IMO, to sneak up on people who think that JavaScript objects are pretty-much the same thing as Smalltalk objects, and show the differences one-by-one, building to a grand reveal that--whoa--there is a big conceptual difference between a dictionary that happens to have methods and a fully encapsulated actor that responds to messages.

TFA links to a post discussion this: http://raganwald.com/2015/05/11/javascript-classes.html

JM2C, YMMV, &c.


Points well presented, noted, and internalized for future use. :-)

Thank you for taking the time to reply. In attempting to preface the content as potentially being controversial, I succeeded in only being trite (or droll or both).

Learning is fun. Embarrassing sometimes, but fun.


Objects in Javascript, while very similar to HashMaps, are not Hashmaps.

` "Prototypical inheiritance" is nothing more than a shallow copy of an associative array. By its very definition, that is _all it is`

No, when you access a property on an object, and that property does not exist on the object itself, Javascript will look for the property on the Object's prototype and the prototype's prototype, etc...

This is very different then a dictionary, where you now have the ability to 'shadow' a property or to change the value of a key in a prototype and have it reflected in all children (which is the exact opposite of a shallow copy).


I believe what you describe can be also described as performing a shallow copy on the prototype which includes the entries from previous copies of the hash map referenced in prior statements.

Unless what transpires is a "back link" to prior definitions such that additions to those prototypes are reflected in subsequent references. Quite frankly, I don't recall off the top of my head which way compliant EMCAScript implementations behave.

> This is very different then a dictionary, where you now have the ability to 'shadow' a property or to change the value of a key in a prototype and have it reflected in all children (which is the exact opposite of a shallow copy).

A dictionary which is shared across all instances would reflect this behaviour, true, but when a dictionary's contents are copied, changes made to the source would not be reflected in the copy (for "first level" key value pairs). I'm pretty sure that adding an indirection to a JavaScript prototype definition (such as placing a hash map in the prototype) would have _its_ key value pairs shared across instances.

But I could very easily be wrong about that.


> Unless what transpires is a "back link" to prior definitions such that additions to those prototypes are reflected in subsequent references. Quite frankly, I don't recall off the top of my head which way compliant EMCAScript implementations behave.

It is:

    var a = {}; var b = {__proto__: a}; console.log(b.x); a.x = 5; console.log(b.x);
(prints undefined then 5)


There are some other points that you are missing, like how do constructors work? If JS objects are just glorified hash maps, why can I write a constructor function to do some stuff when the object is instantiated? The object literal syntax that looks very much like the "hash map" you are describing is exactly the same as creating a new object that extends the Object prototype. In fact, that's pretty much what's going on when you type `{}`.

JavaScript is absolutely an object-oriented programming language, but it's unusual because it's also pseudo-functional, in that functions are first-class citizens. However, functions are also objects. When you type `function` in JS, that is generating an object with the `Function` prototype. You can extend this prototype and call methods on `Function`. That's how Ember.js makes its computed property syntax work, so you can just tack on `.property()` to the end of your function. This would not be possible if JS worked given the semantics you described, because in that story a function is just a function, and not an entire object. JS hides these gory details from you to simplify your experience. Most of the time, you shouldn't have to worry about these kinds of things, but it's fascinating to learn about because there's no other language that works quite like JS.


> If JS objects are just glorified hash maps, why can I write a constructor function to do some stuff when the object is instantiated?

There's no big reason for that, and Object.clone doesn't give that hook, you have to use a wrapper function instead.

> JavaScript is absolutely an object-oriented programming language, but it's unusual because it's also pseudo-functional, in that functions are first-class citizens.

What's unusual about that?

> it's fascinating to learn about because there's no other language that works quite like JS.

That can be said about pretty much any and every language out there.


> While the observations I am about to make likely will be down-voted by some/many in this forum

You are likely to get down voted for this alone but since you are new here, I suggest you read the HN guidelines here: https://news.ycombinator.com/newsguidelines.html


Prefacing a potentially contraversial position is a well established practice to inform a reader that what follows may not be readily accepted.

In retrospect, mentioning down voting was trite. Thank you for being conscientious enough to point this out to me.


I would argue that objects are nothing more than a uniquely identified run-time entity. With that identity, they can easily have their own encapsulated state (since their identity can be used as an address or key into a global map), and can be associated with behavior that is selected dynamically. Compare this with the dual of an object, the value, whose identity is determined by its structure alone (e.g. 1 and 1 are the same values), and so does not allow for state, nor does it allow for dynamic behavior selection without first turning them into objects (aka boxing). The implications of object-ness lead to certain styles of computation (noun-based) just as they do for values (expression oriented and functional).

Objects existed in PL before the more limited kind in Java or even C++, not to mention the powerful but very Java-unlike object systems Self and CLOS that directly influenced JavaScript's design from the beginning.

The only fallacy, I think, is ascribing a notion of objects based on a couple of mainstream data points. Objects are much richer than that.


(Side note: it turns out I can't delete the other message. I must have hallucinated having that ability last night.)

> I would argue that objects are nothing more than a uniquely identified run-time entity. With that identity, they can easily have their own encapsulated state (since their identity can be used as an address or key into a global map), and can be associated with behavior that is selected dynamically.

I largely agree and believe this is pretty consistent with the commonly accepted definition of an object in the Comp Sci sense. There are a couple examples which immediately come to mind (Smalltalk, Objective-C) along with other languages (Ruby, Perl, Python) having the ability to selectively provide equivalent behaviour.

Where I previously said "largely agree", the point where I disagree is when you state "objects are nothing more than a uniquely identified run-time entity." Objects also have associated with them a set of messages which are either intrinsic to the environment's definition of what minimally constitutes any object's behavioural contract, identified by the definition of the object's type, or some mixture of the previous two along with a mechanism to resolve message dispatching.

> Compare this with the dual of an object, the value, whose identity is determined by its structure alone (e.g. 1 and 1 are the same values), and so does not allow for state, nor does it allow for dynamic behavior selection without first turning them into objects (aka boxing).

Here, I think we disagree as not all languages treat values as being disjoint from objects. I realize you mention boxing, which languages such as C# and Java perform for _their_ definition of "plain old data" types, but this is not the same as languages such as Ruby, which represents all values as objects intrinsically.

> The only fallacy, I think, is ascribing a notion of objects based on a couple of mainstream data points.

The fallacy which I mentioned is in thinking that a person has the same checks in JavaScript applied to collaborations as is expected in other OO languages/environments. I view this as a direct consequence of JavaScript objects being hash maps. Supporting this view is:

> A JavaScript object is an unordered collection of variables called named values. (source: http://www.w3schools.com/js/js_object_definition.asp)


> Where I previously said "largely agree", the point where I disagree is when you state "objects are nothing more than a uniquely identified run-time entity." Objects also have associated with them a set of messages which are either intrinsic to the environment's definition of what minimally constitutes any object's behavioural contract, identified by the definition of the object's type, or some mixture of the previous two along with a mechanism to resolve message dispatching.

Good well-developed object abstractions have that feature, but that the intrinsic "objectness" that leads to such a feature being desirable does not. Plenty of us remember working with proto-objects that did not have these features, but the nature of our objects drove us to re-discover this feature on our own (e.g. by rolling your own v-tables for a pointer to a struct in C!).

> Here, I think we disagree as not all languages treat values as being disjoint from objects. I realize you mention boxing, which languages such as C# and Java perform for _their_ definition of "plain old data" types, but this is not the same as languages such as Ruby, which represents all values as objects intrinsically.

Again, I'm going for a definition of objectness. That Ruby treats values as objects isn't necessarily a good thing, and programmers will definitely want to often treat these as values anyways even if the language is resistant to that; e.g. somehow getting 1 == 1 to evaluate as true rather than false! Valueness is just as important as objectness, and in most programs we use both to certain degrees (even if our languages support one over the other).

> JavaScript applied to collaborations as is expected in other OO languages/environments.

We can argue whether it is a good design choice compared to other OO languages/environments, but it definitely makes them "objects."


I want to spend the time to provide a cogent response and it is late where I am at. So this is a "todo" response which will be deleted with a proper one ASAP.


sean,

>implications of object-ness lead to certain styles of computation (noun-based)

i understood that

>just as they do for values (expression oriented and functional).

but wasn't sure what you meant there. could you elaborate?

thanks.


Values lack intrinsic identity, they are basically the antithesis of objects. So say you have a function that computes a value...given the same arguments it will always compute the same value, even if it is not exactly the same one (e.g. 1 and 1 computed via different operations on the machine). The key defining aspect of functional programming is its value orientation (just like the key defining aspect of OOP is its object orientation). When working with values, you'll find that different abstractions and designs make more sense, like the use of functions or expressions for everything, while OOP is more biased to statements and commands.


I think you're confounding the idea of a "dictionary" with the specific data structure of hash map/table. Not all dictionaries are hash maps. There's nothing in the spec that says the dictionary-like properties of an object must be implemented as a hash map. I'm fairly certain that in at least V8 they are not hash maps.


Yes JavaScript objects are weak (allow more, too much) compared to legitimately called OOP ones. But is it really different ? When I see an anonymous function I see a map, lambda calculus classes made me see the world through this choreography of maps. Sure they don't mutate, they rewrap, shadow, etc etc. And JS appears as piece-wise OOP, you have the scope-inheritance mechanism in place. OOP with the larger semantic weight, forbid some things, at least it felt a lot more constrained and a burden in my experience, turning things into class hierarchy silos and unnecessary patterns. What are real OOP semantic guarantees ? static types ?


My main point was not an "attack" on JavaScript objects. Instead, it was to illuminate that how many people write/speak of JavaScript objects use a frame of reference which simply is incorrect.

Your question:

> Yes JavaScript objects are weak (allow more, too much) compared to legitimately called OOP ones. But is it really different ?

Can certainly spark an intriguing conversation indeed. Without making this a treatise, having the likelyhood of mistakes an on-the-fly one would produce, allow me to address this in parts.

> Yes JavaScript objects are weak (allow more, too much) ...

This is the basis of my assertion that semantic guarantees do not exist in this language. Remember, the article's author makes the statement:

> ... modifying the functions bound to properties of the object. This differs from most classical languages, they have a special form (e.g. Ruby’s def) for defining methods.

Significant in this quote is that, in this example, Ruby uses a keyword in its identification of a method. As such, use of the symbol identified by the keyword def allows the Ruby environment to provide a semantic guarantee that its use as a method definition is within the allowable bounds of the language. While this may not sound like much, when presented with thousands of symbols/variables in many systems, the cognitive load is reduced while simultaneously some portion of semantic use is verified by the environment.

> ... compared to legitimately called OOP ones.

I beleive a better categorization of JavaScript would be as "object based", with a non-trivial functional leaning. But that's just me.

> But is it really different ?

Yes, but different !== bad.

> When I see an anonymous function I see a map, lambda calculus classes made me see the world through this choreography of maps. Sure they don't mutate, they rewrap, shadow, etc etc.

IMHO, the significance of immutability is key with the core concepts of functional programming (to which it owes its existence to lambda calculus). Transformations with the certainty that <a href="https://en.wikipedia.org/wiki/Referential_transparency_(comp... transparency</a> is enforced is the foundation which reasoning about complex function interactions is made possible. So when an environment allows effectual modifications _at any point in a call chain_, there is no provable way to show what state a system is in based on the call flow.

This is the dagger with which mutable collaborations stab provability. Of course, all "OOP languages" I am aware of support this style of programming, which is the topic of another thread I suppose.

> What are real OOP semantic guarantees ? static types ?

Many times, but not always. To me, a semantic guarantee is along the lines of the Ruby example explored above. It is when a language's environment provides the developer with feedback when use of a symbol is not conformant with its definition (if known). What JavaScript specifically does not provide is any assistance in identifying this type of issue (albeit trivial):

var foo = doSomethingAndGiveMeBackAFoo ();

// Is this correct? foo.a ();

// Or this? foo.a + 1;




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: