4

I have this code:

// 'Vehicle' object constructor
function Vehicle() {
  this.wheels = 4;
}

// Adding 'setWheels' setter function to set 'wheels' property
Object.defineProperty(Vehicle.prototype, "setWheels", {
  set: function(x) {this.wheels = x}
});

// 'Car' object constructor with 'Vehicle' as prototype
function Car() {}
Car.prototype = new Vehicle;
Car.prototype.constructor = Car;

// myCar inherits 'wheels' property and 'setWheels' method
myCar = new Car();

myCar.setWheels = 2;

I was expecting myCar.setWheels = 2 to alter the inherited property, but instead it sets myCar's local property which shadows inherited one. From what I have read here setting inherited property via setter is possible, which means I am doing something wrong. But what exactly?

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Dima Slivin
  • 599
  • 9
  • 19
  • What do you exactly wants?? This code is perfectly working at my side as expected. it returns Wheels:2 for myCar and Wheels:4 for new Car(). I think its already altering child property. But not parent property. – Laxmikant Dange Oct 15 '14 at 11:16
  • This question is purely educational. I am learning JavaScript and experimenting. And it most likely gives you local property 'wheels:2', which is opposed to inherited one. Try to check it with myCar.hasOwnProperty("wheels"). And my question is about altering _inherited_ value. – Dima Slivin Oct 15 '14 at 11:21

2 Answers2

2

I was expecting myCar.setWheels = 2 to alter the inherited property, but instead it sets myCar's local property which shadows inherited one

Well, you've "called" the setter on myCar, so you are setting its .wheels property.

If you wanted to alter the inherited property, you need to alter it on the object from which it is inherited:

Car.prototype.setWheels = 2;

(Although I've never seen a car with two wheels)

Notice that usually you'd expect instance properties (.wheels set in Vehicle) to be only apparent on instances (like myCar), not on prototypes. You might consider changing your way of inheritance to the commonly accepted one.


The quote you have read at MDN:

Setting a property to an object creates an own property. The only exception to the getting and setting behavior rules is when there is an inherited property with a getter or a setter.

means that an own property will be generated on assignment when there is no setter (but it is a data property or not existing yet). If the property that gets assigned to has a setter defined (either own or inherited), then that setter function will be invoked instead.

Indeed, in your example, no own .setWheels property is getting created on your myCar.

What the setter function does it a whole different question. It can create a property (like yours does, by assigning to .wheels on the current instance, this), or do anything else; including crazy things like redefining itself.

To get the "expected" behaviour, you could use a local variable to store the number of wheels and use a setter/getter property for it:

function Car() {}
var w = 4; // "local", could be in an IIFE
Object.defineProperty(Car.prototype, "wheels", {
  set: function(x) {
    w = x; // no property changes/creations involved
  },
  get: function() {
    return w;
  }
});

// yourCar inherits 'wheels'
var yourCar = new Car();
yourCar.wheels; // 4
yourCar.wheels = 2; // you've got an odd car

var myCar = new Car();
myCar.wheels; // 2 - what's wrong with my car?!

Here, there is only one property - Car.prototype.wheels. Assigning to .wheels on the Car instances will call the shared setter, which updates the shared variable. Notice that such behaviour is usually undesirable, you don't want one instance affect all others.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Again, this question is purely educational. I read this: "Setting a property to an object creates an own property. The only exception to the getting and setting behavior rules is when there is an inherited property with a getter or a setter." on MDN and tried to test it. I am aware of 'commonly accepted' ways of inheritance, I was just curious. – Dima Slivin Oct 15 '14 at 12:01
  • Yes, it is - you are calling the prototype's setter. However, what actually *stores* the value in your example is the `this.wheels = x` - which sets it on the current instance. If you'd use a real getter-setter property which stores it in a local variable, the local variable could be accessed from all objects that inherit the getter - and the change affects all of them. – Bergi Oct 15 '14 at 12:10
  • "...If you'd use a real getter-setter property which stores it in a local variable..." Could you pls provide a correct example? – Dima Slivin Oct 15 '14 at 12:14
  • I think should create property of current instance because if it made changes in the value of base class property that is its referring base class variable memory, which will affect in all childrens of Vehicle class. Please correct me if I am wrong – Laxmikant Dange Oct 15 '14 at 12:20
  • Turns out I misunderstood the concept and purpose of getters and setters. Now it's all clear. An accurate and complete answer. Thanks, mate. – Dima Slivin Oct 15 '14 at 12:57
0

You created new instance of Vehicle so you can't directly change it. As new Vehicle returns object having property wheels, here you are setting it to Car.prototype means you are creating a function having some prototype properties returned by new Vehicle. so setWheels property will also get copied to Car.prototype. hence this operator in setWheels refers to Car and when you set value using setWheels, it creates an property wheels for car (overwrites uses copied/inherited property) so it is showing that wheels is property of Car. try to console myCar.hasOwnProperty("wheels") before and after setting value by setWheels.

Laxmikant Dange
  • 7,606
  • 6
  • 40
  • 65