Thank for your patience. I think I were just scared with what Crockford wrote. :)
On Thu, Dec 23, 2010 at 11:42 PM, Dmitry A. Soshnikov <dmitry.soshni...@gmail.com> wrote: > On 23.12.2010 17:54, Yu-Hsuan Lai wrote: > > I think I have totally understood your code, but is this the using > "new" which "Good Part" try to avoid? > > I think the book you read consider `new` as `evil` because of two reasons: > (1) to avoid a similarity with a class-based systems such as Java (to setup > your mind to think in a prototype-based paradigm), and (2) to scare children > ;). > > The first reason could be considered as a noble only if there would be no > one "but...". As you know, the ability to _generate_ objects isn't yet > considered as an ability to _classify_. In case of several (many) similar > objects with the same state, we need a some convenient way to generate > objects. E.g.: > > var point = {x: 1, y: 2}; > > If we need several points: > > var a = {x: 1, y: 2}; > var b = {x: 3, y: 4}; > var c = {x: 5, y: 6}; > > But obviously, a copy-paste code reuse stylistic isn't a professional way to > program (what if you need 100, 1000 such objects?). Of course we need an > elegant way to reuse the generation of points. The easiest way is to use a > simple function (as you always do in case when the code is repeated more > than two times -- so-called a "rule of two": "If something apears in the > code more than two times -- move (encapsulate) it into a function"): > > function makePoint(x, y) { > return { > x: x, > y: y > }; > } > > var a = makePoint(1, 2); > var b = makePoint(3, 4); > var c = makePoint(5, 6); > > I guess the profit is obvious -- if later the the internal state of a point > will change, we should edit only one place. So, the main purpose of a > constructor (once again) is to conveniently reuse the code and to generate > objects of the same structure. > > However, to be able to classify your objects (i.e. to distinguish them from > other objects with the same structure), you need to use a some > classification tag (simply a some property, which help to uniquely > differentiate your objects). You could place it directly on the point object > itself, but it's not efficient since the same property is created every time > on every object. Instead, you may create a helper shared object which will > store common properties of all points. To not place this helper object in > the global scope, you may store it as a property of your `makePoint` > function. Thus, a helper object is called a `prototype` and the > classification tag -- `constructor`: > > makePoint.prototype = { > constrcutor: makePoint > }; > > And modified way of creation: > > function makePoint(x, y) { > return { > __proto__: makePoint.prototype, > x: x, > y: y > }; > } > > Then you need to implement the ability to get the classification tag > directly from the instances. It's simple: if a property isn't found on the > object, continue the lookup in its __proto__ link. > > a.constructor // a.constructor -> not found, a.__proto__.constructor -> > found == makePoint. > > Having implemented this, you may want to sugar somehow your "makePoint" > factory. You can: (1) remove "make" prefix (replace it with `new` keyword), > (2) make `return` implicit, (3) set __proto__ also implicitly, (4) do not > explicitly use {} every time, but use a special keyword to reference the > newly created object (e.g. `this`). That's how you'll get the constructors > system implemented in JS: > > function Point() { // no "make" > this.x = x; > this.y = y; > } > > var a = new Point(1, 2); > var b = new Point(3, 4); > var c = new Point(5, 6); > > a.constructor // Point > > So from this viewpoint, you see that `new` keyword (if you really understand > "what's is going on here" but not just want to scare children which didn't > heard that word "prototype") isn't evil at all. It's just a sugar for your > factory function. There is no a big difference between "make me a point" and > "construct me a new point". > > Of course, if you don't need a classification, you may simply inherit from > other objects just setting their __proto__ reference (what exactly is made > inside the `Object.create`). > > By the way, ECMAScript itself classifies its objects. And not surprisingly > with the classification tag which is called the same -- [[Class]]. E.g.: > > var a = {}; > var b = []; > > // both are objects > alert([typeof a, typeof b]); // "object", "object" > > // but have different classification tags > var getClass = Object.prototype.toString; > > alert([getClass.call(a), getClass.call(b)]); // "[object Object]", "[object > Array]" > > "An even better coping strategy is to not use new at all." > In fact, I don't regard your classical implementation bad. This is the > reason why I'm so confused. > > > Only you decide what is better for your system -- where you need classified > objects or you just want to inherit them in the unclassified manner. > > Is this an "even better strategy"? > var a={x:10}; > b=Object.create(a); > b.x = 20; > b.y = 30; > > > Yes, quite a good solution also. Why not? > > I can't realize its advantages. Crockford gave me am impression: "new > is evil, prototype is beautiful." > > Always remember that strong phrases are not analytic. > > (he put "new" in the "bad parts") > Did he exaggerate or I misunderstand him? > > > Analyze. Once you see the reasons for what this or that construction is here > (in the language), you will have your meaning on the question and may decide > yourself what is bad and what's not. > > (I know in previous post you have tried to answer me... but maybe I'm > not enough clever to understand it) > > > The topic in truth is easier than it looks and easier than some trying to > explain it in books. As you saw, there is no big differences between > classical and protoypal approaches. Again, the main difference is in the > classified and unclassified concepts. And all the other stuff (sugar for > creation, etc) is derived. > > Dmitry. > > On Thu, Dec 23, 2010 at 8:13 PM, Dmitry A. Soshnikov > <dmitry.soshni...@gmail.com> wrote: > > On 23.12.2010 14:54, Yu-Hsuan Lai wrote: > > Where is " context of your child object"? > > > It's a this value. > > 1. Parent constructor: > > function A(x) { > this.x = x; > } > > A.prototype.foo = function () { > return this.x; > }; > > // and instance of the constructor "A" > var a = new A(10); > > // has an own "x" property > alert(a.x); > > // and a classification tag "constructor", which > // is an inherited property placed on the prototype > alert(a.constructor === A); // true > > 2. Child constructor > > function B(x, y) { > > // apply the parent constructor > // in context of the child object > A.apply(this, arguments); > > // create an own property > this.y = y; > } > > // inherit from A.prototype > B.prototype.__proto__ = A.prototype; > > var b = new B(20, 30); > > // "b" object has own "x" and "y" properties > alert([b.x, b.y]); // 10, 20 > > // and "classified" as "B" > alert(b.constructor === B); // true > > Notice how "b" got its "x" property via A.apply(this, arguments)? This is > called to apply a function in context of the needed object (`this` value > references to a newly created object, that is, to "b" at working of B > constructor) . > > P.S.: notice also, I used non-standard inheritance way with __proto__ to > simplify explanation. > > Dmitry. > > On Thu, Dec 23, 2010 at 6:37 PM, Dmitry A. Soshnikov > <dmitry.soshni...@gmail.com> wrote: > > On 23.12.2010 11:37, Yu-Hsuan Lai wrote: > > In fact, even though I just want some public variants, I still have the same > problem. > var obj = {a:1,b:2,c:3 ... some methods...}; > obj2 = Object.create(obj); > obj2.a is referred to obj.a, right? If I want another instance, I have to > write obj2.a = 1; > > Yes, this exactly one of the differences. In a class-based system all > properties are copied to the class descendant (even if some of them are not > needed at deeper classes). In a prototype-based system the state > (properties) as well as behavior (methods) are inherited. > > But if the object is very "big"? Write a function to assign all variants? Is > it "constructor"? > > A constructor is used to generate (usually more than one) objects of a > needed "classification" (a "classification" tag which may help to > distinguish one object from another is stored usually in the inherited > `constructor` property of an object, e.g. a.constructor == A ? where `A` is > a constructor of `a` instance). It's a factory which generates the objects. > If you need only one unclassified object, there is no big need in the > constructor. You may use e.g. an object initialiser to create an object: a = > {}. To inherit from another, you (as you know) may use Object.create(proto, > [props]). > > To create an own state in this case, yes, you should manually copy needed > properties to the child object. In case of using constructor, you may apply > needed function in context of your child object. Though, it isn't differ > much from the same manual creation of needed own properties -- in any case > you describe them in the parent constructor. > > > Once I implement these all, my prototypal OO still is different from > classical OO? > > No so much. You may generate (with constructors) and "classify" (with > classification tag -- the property "constructor") your objects. You don't > inherit the state but have the own one for child objects. You inherit > methods with linear systematized chain. It's a class-based system. I.e. with > a prototype-based system it's easy to implement the class-based system. But > not a vice-versa. > > Dmitry. > > On Thu, Dec 23, 2010 at 3:14 PM, אריה גלזר <arieh.gla...@gmail.com> wrote: > > This is exacatly the point - you create the methods and the variable > together, so either you get a copy of all of them, or you get a new > instance. > But if you want a 'private' variable for each instance, the only way you are > going to achieve this (I think) is by creating a separate closure for each > object creation. So you can either do the above second solution, or you can > do > var obj = { > getA : function getA() { > return this.a; > }, > setA : function setA(b) { > a = this.b; > } > }; > > function F(){ this.a = 'a';} > for (i =0; i<10;i++) x.push((function(){ F.prototype = obj; return new > F();})(); > > And you will still be exposing a in the end. But the point is, this is much > less readable and performance-wise I don't think it really matters, so your > second pattern is good enough IMO. > > note - this list beeing so heavy on js wizards, I'm always a little afraid > of posting comments here... > > > On Thu, Dec 23, 2010 at 8:23 AM, Yu-Hsuan Lai <rainco...@gmail.com> wrote: > > I'm trying use prototypal inheritance instead of classical one. But I'm > still confused. > I can't complete very very very small tasks, like this one: > Create 10 copies of a object(with a private variant and public functions to > access it) in an array. > I have two way to approach it, first is to use Object#create: > var x=[]; > x[0]=(function () { > var a=10; > return { > getA : function getA() { > return a; > }, > setA : function setA(b) { > a = b; > } > }; > })(); > for(var i=1; i<10; i++) > x[i] = Object.create(x[0]); > But all 10 objects' "a"s refer to a single integer. Tragedy. > My second way is call a function which return a object 10 times: > function createX() { > var a=10; > return { > getA : function getA() { > return a; > }, > setA : function setA(b) { > a = b; > } > }; > } > var x=[]; > for(var i=0; i<10; i++) > x[i] = createX(); > It works. But every x has its own "getA" and "setA" instance. In contrast to > the former, it costs more memory. > I know it maybe doesn't matter. But knowing prototypal OO can use only one > instance, creating 10 let me regard me as a stupid. > Except the two methods, the only one method I can figure out is... classical > OO. > Is it avoidable? > > > -- > Lai, Yu-Hsuan > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > > > -- > Arieh Glazer > אריה גלזר > 052-5348-561 > http://www.arieh.co.il > http://www.link-wd.co.il > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > > > -- > Lai, Yu-Hsuan > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > > > -- > Lai, Yu-Hsuan > > > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > > > > > -- > To view archived discussions from the original JSMentors Mailman list: > http://www.mail-archive.com/jsmentors@jsmentors.com/ > > To search via a non-Google archive, visit here: > http://www.mail-archive.com/jsmentors@googlegroups.com/ > > To unsubscribe from this group, send email to > jsmentors+unsubscr...@googlegroups.com > -- Lai, Yu-Hsuan -- To view archived discussions from the original JSMentors Mailman list: http://www.mail-archive.com/jsmentors@jsmentors.com/ To search via a non-Google archive, visit here: http://www.mail-archive.com/jsmentors@googlegroups.com/ To unsubscribe from this group, send email to jsmentors+unsubscr...@googlegroups.com