0
function NamedRoundedBlock(){
    var name = this.makeFeild("name");
    name.className = "Block NamedRound name";
    this.element.className = "Block NamedRound root";
    this.element.appendChild(name);
}
NamedRoundedBlock.prototype = new Block();
NamedRoundedBlock.prototype.constructor = NamedRoundedBlock;

There's the code, anyone know what I've done wrong?

My problem is that if I make two NamedRoundedBlock objects and change the this.element property of one (by changing an attribute or something) the other's will change too.

Also, a little additional detail, this.makeFeild and this.element are both set in Block

user1877408
  • 137
  • 1
  • 11
  • 3
    I have no idea what you did wrong, because you didn't say what the problem is. – Chris Hayes Jan 04 '14 at 01:35
  • The title is throwing me off, too. Objects don't magically change their prototypes. Can you clarify? – Ray Toal Jan 04 '14 at 01:37
  • Sorry, I'll edit the question a bit – user1877408 Jan 04 '14 at 01:37
  • Thanks for the clarification. JavaScript is behaving as advertised here. The prototype is just the place for shared properties. Changes you make in the prototype are seen by all objects. – Ray Toal Jan 04 '14 at 01:45
  • That's a bit annoying. What's the best way around it? – user1877408 Jan 04 '14 at 01:52
  • I'll write an answer, once sec. – Ray Toal Jan 04 '14 at 02:00
  • Answered but question just got marked as a dupe. – Ray Toal Jan 04 '14 at 02:12
  • You have just found one of the reasons why you should not create an instance of Parent to set the prototype part of Child inheritance. You can still do `Parent.apply(this,arguments);` and shadow Parent instance specific members but you still should not do `Child.prototype=new Parent();` use Object.create with a polyfil if needed: http://stackoverflow.com/a/16063711/1641941 – HMR Jan 04 '14 at 04:05

2 Answers2

1

The prototype is the place for shared properties.

Consider:

var protoCircle - {x: 0, y: 0, radius: 1}

This means every circle will have these properties as defaults. So if I make circle with that prototype:

var c1 = Object.create(protoCircle);
c1.x = 3;

var c2 = Object.create(protoCircle);
c2.y = 5;

then circle c1 is at (3,0) with radius 1 and c2 is at (0,5) with radius 1. That's because c1 has only one own property (x) and two inherited properties (y and radius) which it picks up from its prototype. If I change protoCircle.radius then that change will be seen by the two circles. That is the way JavaScript is designed! This design allows a whole bunch of objects to share a default value so you don't have to store it in each object. You just put the properties unique to each object inside each object and let the default properties be shared in the prototype. In the case above, if 99% of the circles have a radius of 1, then we don't have to store radii in our individual circles.

In your case you put a property called element in a prototype. All objects that share that prototype will have the same value for element. So if you say

x.element.className = 'something'

then that does effectively make y.element.className be something as well, assuming y shares the same prototype as x.

If you want each of the named rounded blocks to have different elements then you need to do this:

function NamedRoundedBlock(){
    ...
    this.element = {}
    this.element.className = "Block NamedRound root";
    this.element.appendChild(name);
}
Ray Toal
  • 86,166
  • 18
  • 182
  • 232
0

Check out Traditional OOP Inheritance in JavaScript

The above blog post may help answer some of your questions.

It elaborates particularly on defining a new constructor for an object, which "inherits" from a parent. Is that one of your questions? Take this for example:

NamedRoundedBlock.prototype = Object.create(
    Block.prototype,
        {
            "constructor": { 
                configurable: true,
                enumerable: false,
                writable: true,
                value: 'NamedRoundedBlock'
            }
        }
);

The above created an object based on Block's prototype, but it defines its own constructor, and also sets it as not enumerable.

Also, should the first line be something like this?:

function NamedRoundedBlock() {
    this.name = this.makeFeild("name");
    //etc.

Additionally, independent of the issue, I'd be careful with the spelling of "Feild" (spelled "Field"), as spelling issues can sometimes cause hard-to-find bugs later in the code.

Josh Beam
  • 19,292
  • 3
  • 45
  • 68
  • Links are bad answers! Try to elaborate in your post, as links can and do change. – James Bruckner Jan 04 '14 at 01:40
  • Second parameter in Object.create does not work in older browsers and a good polyfil should throw an error: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Polyfill (look at throw new Error) – HMR Jan 04 '14 at 04:07