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

Reply via email to