Hi, I'll do a 2 parts answer. First, I'll answer the blog post, second, I'll try to take a step back and discuss composition in JavaScript.
=== Part I === Le 16/03/2012 17:04, Kevin Smith a écrit : > Rather than abuse your inbox, I published this as a blog entry: > > http://blog.khs4473.com/2012/03/using-object-literals-as-classes.html > > Summary: It has been suggested that extended object literals can be > used to define class-like abstractions, and that consequently class > syntax is not necessary. I'm not sure the conclusion has ever been that strict. Having the proto and extend operator version is not mutually exclusive with a class syntax. I don't remember having read that at least. > I analyze the implications from the point of view of a library developer. > > Comments? The "Class"-like libraries started to compensate missing things in the language specifically when it came to loosely-coupled composition of abstractions. New language features (the proto operator, the extend operator, maybe even traits if they make it to the language) are here to fill a gap in the language expressiveness. I'm a bit surprised by the approach of the blog post which consists in studying how new features will fit in or help ameliorate a Class library. "`useMethod` calls a private method here. But does this work? Privately named properties aren't enumerable and don't show up in Object.getOwnPropertyNames. *My class library works* by reading the keys from the input object and attaching them to a new object with the correct prototype chain. But..." (emphasis added) => your library works in a certain way and you won't be able to use your exact implementation in concordance with how private names have been defined. Maybe the private name feature could be reconsidered or maybe your implementation could be reconsidered. ----- _new : function(textview){ TextRange.call(this); EventTarget.call(this); EventSubscriber.call(this); this.blabla = ... } ----- When I read this code, questions that comes to mind : What if conflicting names are defined in the TextRange, EventTarget or EventSubscriber? Does the order matter? Certainly so and it would make your composition mechanism not that declarative. Anyway, the answers do not really matter. What does is that it's not obvious from reading the code what happens. It's fine-ish for a library of your choice, but it's annoying when discussing language features. "`super.constructor` is annoyingly verbose, and I might as well just use BaseClass.call(this). No gains there." => super will be a keyword. As such, it can be highlighted by IDEs. It can help readability. It also avoids the repetition: ----- { extends: TextRange, _new: function(textView) { TextRange.call(this); } } ----- With super, you know you're calling the thing you extend from. Change it in one place, it applies everywhere unlike in your case where you have to remember to change something in 2 places. " For library authors, object literal extensions do not provide a replacement for class construction libraries." => This conclusion is rather surprising. You haven't assessed object literal extensions to solve a problem, but just tried to see how they impact your Class construction library. "The individual extensions provide some support in the form of shorter method syntax and static delegation, but fall short of providing the tools to create a fully featured class library. " => It wasn't a goal. If creating a fully-featured class library had been a goal, I think there would be a strawman for that. "Furthermore, it's not clear at the present time that prototype delegation is useful outside of the context of class-like abstractions, and the necessity of rebinding "super" for every method indicates that the "super" semantics are being defined at the wrong level of abstraction." => ... or that you're trying to use a feature in a way it was not design for. In which case, don't use the feature. === Part II === So, let's take a step back. Before Class libraries, JavaScript did not have an easy way to express something like: "I want a Ninja to be a Person with a sword". I can think of these ways (not an exhaustive list): ----- // 1) with methods as own properties of persons function Ninja(){ Person.call(this, "Joe"); // getting all persons properties // This style forces a bit objects to only be normal objects // They can't be arrays, functions, DOM objects or proxies for instance this.sword = "Excalibur"; } // 2) with methods as own properties of persons function Ninja(){ var init = {}; // could be anything, like arrays or functions. var p = new Person("Emily"); // pour all p properties in 'init' with a for-in loop or whatever method // alternatively copy values and forward methods this.sword = "Excalibur"; } // 3) with person methods in Person.prototype function Ninja(){ Person.call(this); // just properties this.sword = "Excalibur"; } Ninja.prototype = Object.create(Person.prototype) Ninja.prototype.method = function(){}; /* Encapsulation is lost in that case since the inherited methods need to know the state of the object which has to be public */ ----- All of this is awkward to say the least. Comments and discussion welcome on this list. Came along Class libraries which provided something a bit more declarative, but had one of the limitations of the above method anyway. Fast forward to 2012. How do I define a Ninja with the new operators? ---- var Ninja = Person <| function(){ super.constructor(); this.sword = "Excalibur"; } ---- Encapsulation will not be compromised. Additionally private names will work fine here. If the base class is Array or WeakMap, it works as well. In the end, JavaScript is still not a good language for classes library, but I think the new operators help solving most (maybe not all) problems Class libraries were initially introduced for. David _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss