Object instances share sub-properties? [duplicate] - javascript

This question already has answers here:
Javascript object members that are prototyped as arrays become shared by all class instances
(3 answers)
Closed 8 years ago.
Given the following code:
var Car = function() {};
Car.prototype = {
wheels: {
rims: 'steel'
}
}
var volvo = new Car;
var mercedes = new Car;
volvo.wheels.rims = 'aluminium';
console.log(volvo.wheels.rims, mercedes.wheels.rims); // 'aluminium', 'aluminium'
Can you explain why instance mercedes of Auto automatically inherits the sub-property definition for rims from volvo?
Note the following code works as expected with same setup:
volvo.wheels = 4;
console.log(volvo.wheels, mercedes.wheels); // 4, Object { rims: 'steel' }

You only ever create a single object for wheels.
You assign this object to the prototype, so every instance inherits its value.
Javascript will never automatically copy an object.
Instead, you should create the object in the constructor so that you get a new object for each instance.

Related

Javascript object oriented programming showing undefined [duplicate]

This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 7 months ago.
I am new to javascript oop
i have been trying to get the desired value but it gives me undefined
class person {
constructor(isGreat, brain, personality) {
this.isGreat = isGreat;
this.brain = brain;
this.personality = personality;
}
getDetails(req) {
this.req = req;
let dic = {
isGreat: this.isGreat,
brain: `they have ${this.brain} brain`,
personality: `they have ${this.personality} personality`,
};
return dic.req;
}
}
let person0 = new person(true, "massive", "great");
console.log(person0.getDetails("isGreat"));
req can get read but dic.req shows undefined
The problem is console.log shows undefined.
dic doesn't have a req property. If you want to get a property whose name is stored in req variable, use the following syntax:
dic[req]
Just like accessing array members. In fact, a.b and a['b'] are equivalent in JavaScript.
BTW: The assignment this.req = req is not necessary.
You are returning the req property of your object, not the property with the key stored inside req. You need to use square brackets to get the index stored inside req.
return dic[req]
This is because it gets parsed as dic['isgreat'] rather than dic['req'].

How can I have two objects access the same array [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 3 years ago.
Class A is instantiated to an object that has an array named this.people that is filled with a bunch of data. Class A instantiates an object of class B and this.people is passed to it's constructor. If object B updates the array, when object A updates it, it overwrites the changes from object B. How can I fix this?
That happens because you're passing a reference of A's people array to B's constructor. You want to make either a "shallow copy" or a "deep copy" of A's people array, since you want B's people array contents to be different.
With a "shallow copy" you copy all of the primitive values in the array to the new one, but if you have compound values (arrays or objects) inside the array, then only the reference to them will be copied, so any changes that you do to the compound values will be reflected in both A and B. With a "deep copy", both primitive and compound values (and not just their references) will be copied to a new place in memory.
If you don't have objects and arrays inside the people array, you can do a shallow copy using Array.from(a.people). Otherwise, you can do a deep copy with JSON.parse(JSON.stringify(a.people))
Snippet:
class B {
constructor(_people) {
// shallow copy:
this.people = Array.from(_people);
// deep copy:
//this.people = JSON.parse(JSON.stringify(_people));
}
}
class A {
constructor() {
this.people = [];
}
func() {
this.objB = new B(this.people);
//do something
}
}
// Usage Example
let objA = new A();
objA.people.push("A");
objA.func();
objA.objB.people.push("B");
console.log(objA.people.toString());
console.log(objA.objB.people.toString());
Some helpful links:
https://medium.com/#gamshan001/javascript-deep-copy-for-array-and-object-97e3d4bc401a
https://dev.to/samanthaming/how-to-deep-clone-an-array-in-javascript-3cig
Give each class its own version of people
class A{
constructor(){
this.people = ["bob","jane","john"]
this.objB = new B(this.people)
}
}
class B{
constructor(people){
this.people = people
}
}
let objA = new A()
objA.objB.people.push("a")
objA.people.push("b")
console.log(objA.people, objA.objB.people)
Pass the array by value with destructuring.
class Family {
constructor(people) {
this.people = people;
}
}
let members = ["mom", "dad"];
let smiths = new Family(members);
let joneses = new Family(smiths.people); // pass by reference
joneses.people.push("Billy");
console.log(smiths.people); // changes to ["mom","dad","Billy"]
let wilsons = new Family([...smiths.people]); // pass by value
wilsons.people.push("Suzy");
console.log(smiths.people); // remains ["mom","dad","Billy"]

using this keyword in object literal javascript [duplicate]

This question already has answers here:
Assigning the value of another key in javascript [duplicate]
(2 answers)
Closed 7 years ago.
According to me this is only being used if you need to call constructor like below
var dogObj = function(){
this.bark = "woof";
}
var dog1 = new dogObj();
console.log(dog1.bark);
Is there any cases where I use this on object literal?
var bark = {
this.bark = "dog"
}
Is above code valid? If yes,how do I call it?
you can use
var bark = {
bark : "dog"
}
and call it like
console.log(bark.bark)
this.bark = "woof";
Is not valid.
You have try something like below
var dog = {
bark : "dog"
}
And then you can access like console.log(dog.bark)
Once you formed any json string you can validate the sting using http://jsonlint.com/ just place your json string and the click on validate.

Safely inheriting prototypes in JavaScript [duplicate]

This question already has answers here:
Benefits of using `Object.create` for inheritance
(4 answers)
Closed 8 years ago.
Let's say I'm shooting for some basic inheritance in my application, I could achieve this by setting the prototype of my child to the parent.
// Parent "class"
var Car = function(year) {
this.year = year;
};
Car.prototype.drive = function() {
console.log('Vrooom');
};
// Child "class"
var Toyota = function() {
Car.apply(this, arguments);
};
Toyota.prototype = Car.prototype;
var myCar = new Car(2010), myToyota = new Toyota(2010);
myCar.drive(); // Vrooom
myToyota.drive(); // Vrooom
Seems to work, but is obviously bad because if I set a new method on my Toyota.prototype, it will be set on Car's prototype.
Toyota.prototype.stop = function() {
console.log('stooop');
};
myCar.stop(); // stooop <--- bad
myToyota.stop(); // stooop <--- good
To solve this, instead of Toyota.prototype = Car.prototype; I can add an intermediary:
var ctor = function() { };
ctor.prototype = Car.prototype;
Toyota.prototype = new ctor();
Toyota.prototype.stop = function() {
console.log('stooop');
};
myCar.stop(); // throws undefined error <--- good
myToyota.stop(); // stooop <--- good
But I don't understand why this works. ctor creates a new instance with its prototype set to Car's prototype, and then Toyota sets its prototype to that new instance.
But why create an empty object with a prototype that gets referenced by Toyota's prototype?
Why doesn't setting a new method on Toyota set it on Car like it does in the first example?
What if I want several layers of inheritance, it seems like I need to glue them together with a new ctor every time?
But why create an empty object with a prototype that gets referenced
by Toyota's prototype?
Because if you do this: Toyota.prototype = new Car();
Now Toyota's prototype is an instance of Car, which means that in addition to having Car's prototype in the chain, it also has any properties set in the Car constructor itself. Basically you wouldn't want Toyota.prototype to have a property called year like so: Toyota.prototype.year. Because of this it's a lot better to have an empty constructor like so:
var ctor = function() { };
ctor.prototype = Car.prototype;
Toyota.prototype = new ctor();
Now Toyota.prototype has the new ctor() instance as it's prototype, which in turn has Car.prototype in its own chain. This means that instances of Toyota now can execute methods that exist in Car.prototype.
Why doesn't setting a new method on Toyota set it on Car like it does
in the first example?
With this: Toyota.prototype = Car.prototype; you're setting Toyota' prototype to be the same exact object as what Car.prototype contains. Since it is the same object, changing it in one place also changes it everywhere else. This means that objects are passed be reference and not by value, which is another way of saying that when you assign an object to 3 different variables, it is the same object regardless of which variable you use. Strings for example are passed by value. Here is an example with strings:
var str1 = 'alpha';
var str2 = str1;
var str3 = str1;
str2 = 'beta';
// Changing str2 doesn't change the rest.
console.log(str1); //=> "alpha"
console.log(str3); //=> "alpha"
console.log(str2); //=> "beta"
Now compare to objects and their properties;
var obj1 = {name: 'joe doe'};
var obj2 = obj1;
var obj3 = obj1;
console.log(obj1.name); //=> "joe doe"
console.log(obj2.name); //=> "joe doe"
console.log(obj3.name); //=> "joe doe"
obj2.name = 'JOHN SMITH';
console.log(obj1.name); //=> "JOHN SMITH"
console.log(obj2.name); //=> "JOHN SMITH"
console.log(obj3.name); //=> "JOHN SMITH"
What if I want several layers of inheritance...
Here is another way of creating layers of inheritance:
var Car = function(year) {
this.year = year;
};
Car.prototype.drive = function() {
console.log('Vrooom');
};
var Toyota = function() {
Car.apply(this, arguments);
};
// `Object.create` does basically the same thing as what you were doing with `ctor()`
// Check out the documentation for `Object.create` as it takes a 2nd argument too.
Toyota.prototype = Object.create(Car.prototype);
// Create instances
var
myCar = new Car(2010),
myToyota = new Toyota(2010);
// Add method to Toyota's prototype
Toyota.prototype.stop = function() {
console.log('stooop');
};
Let's try it out now:
myToyota.stop(); //=> 'stooop'
myCar.stop(); //=> 'TypeError: undefined is not a function'
myCar.drive(); //=> Vrooom
myToyota.drive(); //=> Vrooom
Your problem is the following line:
Toyota.prototype = Car.prototype;
and then later modifying this object:
Toyota.prototype.stop = function() {
console.log('stooop');
};
because in the first line, you set Toyota.prototype to the exact same object as Car.prototype. This is not a copy, it is a reference to the same object! So as soon as you modify stop on Toyota.prototype, you actually modify both Toyota.prototype and Car.prototype, because it is one and the same.
What you'd really want to do is replacing the first line with:
Toyota.prototype = Object.create(Car);
so that you now have the prototype of Toyota point to the Car function, as it should, instead to Car's own prototype. Congratulations, you've used the prototype chain!
(Note: Using Object.create to do class inheritance is inherently more stable and reliable, because it does not run any code that you might have contained in the Car function, but only sets up the prototype link.)
For further discussion on what is happening here exactly, and why you might be better off not using "class inheritance" in JS at all, you might want to read Chapters 4-6 of You Don't Know JS (objects & prototypes).
On your last question: "What if I want several layers of inheritance, it seems like I need to glue them together with a new ctor every time?" – yes, you'd need to do this, and this is the standard pattern for (fake) classes and inheritance in JavaScript.

JavaScript - pass objects by reference [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I store reference to a variable within an array?
Consider the following code:
var a = 'cat';
var b = 'elephant';
var myArray = [a,b];
a = 'bear';
myArray[0] will still return 'cat'. Is there a way to store references in the array instead of clones, so that myArray[0] will return 'bear'?
While I agree with everyone else saying that you should just use myArray[0] = whatever, if you really want to accomplish what you're trying to accomplish you could make sure that all you variables in the array are objects.
var a = {animal: 'cat'},
b = {animal: 'elephant'};
var myArray = [a, b];
a.animal = 'bear';
myArray[0].animal is now 'bear'.
No. JavaScript doesn't do references in that way.
Nope, it is not possible. JavaScript doesn't support such references.
Only objects are stored as references. But I doubt it's what you want here.
You've kind of answered your own question. If you want myArray[0] to equal bear, then set:
myArray[0] = "bear";
Even if your array holds references to objects, making a variable refer to an entirely different object would not change the contents of the array.
Your code does not modify the object variable a refers to. It makes variable a refer to a different object altogether.
Just like your JavaScript code, the following Java code won't work because, like JavaScript, Java passes references to objects by value:
Integer intOne = new Integer(1);
Integer intTwo = new Integer(2);
Integer[] intArray = new Integer[2];
intArray[0] = intOne;
intArray[1] = intTwo;
/* Make intTwo refer to a completely new object */
intTwo = new Integer(45);
System.out.println(intArray[1]);
/* output = 2 */
In Java, if you change the object referenced by a variable (instead of assigning a new reference to a variable) you get the behavior you desire.
Example:
Thing thingOne = new Thing("funky");
Thing thingTwo = new Thing("junky");
Thing[] thingArray = new Thing [2];
thingArray[0] = thingOne;
thingArray[1] = thingTwo;
/* Modify the object referenced by thingTwo */
thingTwo.setName("Yippee");
System.out.println(thingArray[1].getName());
/* output = Yippee */
class Thing
{
public Thing(String n) { name = n; }
private String name;
public String getName() { return name; }
public void setName(String s) { name = s; }
}

Categories

Resources