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