In the below code, how is objA.foo value is set to 'bar'? (No-vice Javascript developer). Which concept or functionality in JS sets the value of objA property to 'bar'?
var objA = Object.create({
foo: 'foo'
});
var objB = objA;
objB.foo = 'bar';
console.log(objA.foo);
console.log(objB.foo);
var objB = objA does not create a copy of the object. It holds a reference to objA. Modifying the object through the reference changes it for both variables holding a reference to that object.
To clone the Object, you can use JSON.parse(JSON.stringify(obj)).
var objA = Object.create({
foo: 'foo'
});
var objB = JSON.parse(JSON.stringify(objA));
objB.foo = 'bar';
console.log(objA.foo);
console.log(objB.foo);
You can also use Object.assign({}, obj).
var objA = Object.create({
foo: 'foo'
});
var objB = Object.assign({}, objA);
objB.foo = 'bar';
console.log(objA.foo);
console.log(objB.foo);
See the documentation.
var objB = objA;
You're actually creating a reference to objA. If you'd like to copy the object without a reference you can use the spread syntax:
var objB = {...objA};
Also, see: How do I correctly clone a JavaScript object?
Related
Situation:
I have multiple JS-Objects with the same structure.
In all of those Objects there's a property called console.
I'd like to assign a value (the same value) to each of these properties.
Please find below the structure of my code:
NameOfMyObject = function() {
return {
actions: null,
console: null,
init: function() {},
//object specific functions
}
};
My Problem:
Currently I'm assigning the value manual, but I want do do it generic.
Code snippet
this.console = console;
this.actions.console = console;
this.fixtures.console = console;
How can I access the properties of my objects?
I hope I asked my question clear enough.
Here is how you would share a property across objects:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
Object.getPrototypeOf(obj1).console.id = 13; // Assign a value once...
console.log(obj1.console.id); // ... and it exists on both instances
console.log(obj2.console.id);
The shared property is on the prototype object.
Instead of Object.getPrototypeOf(obj1) you can of course use MyClass.prototype, since you know that obj1 was created by MyClass. They give the same prototype object.
If your property always has an object as value and you don't need to replace that value, only mutate it by setting properties on that object, then you don't need to explicitly reference the prototype to set a new value.
So this works:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
obj1.console.id = 13; // Assign a value once... (getting console from the prototype)
console.log(obj1.console.id); // ... and it exists on both instances
console.log(obj2.console.id);
But if you change console itself, you'll be setting it on the instance, not on the prototype:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
obj1.console = { id: 13}; // Setting an instance property now
console.log(obj1.console.id); // ... and it does not exist on both instances
console.log(obj2.console.id); // == undefined
So if that kind of assignment should still work on the prototype, you need to use the first code block with Object.getPrototypeOf or MyClass.prototype.
As the subject, is it OK to use ... in that way to copy properties in an object to another?
Chrome always throws syntax error when I was trying to use it in an object like:
var a = function(){
return {c: 2};
}
var b = {...a()};
In es2018 the spread syntax if applied to an object behaves like object.assign.
var obj1 = { a: 1 }
var obj2 = function() { return {b:2} };
var obj3 = { ...obj1, ..obj2 }
The result would be a new object with combine properties of obj1 and obj2. So obj3 would now be { a:1, b2 }.
var object1 = {
name: "abc",
age: 21
}
var Object2 = function() {}
Object2.prototype = object1;
Object2.prototype.hello = function() {
console.log("Hello");
}
var obj = Object.create(object1);
for (var prop in obj) {
console.log(prop + ": " + obj[prop]);
}
The output of this code is:
name: abc
age: 21
hello: function () {
console.log("Hello");
}
Obj is created by setting its prototype as object1, which doesn't have the 'hello' function, so why is it listed in the output? If I comment out 'Object2.prototype = object1;', the 'hello' function no longer shows in the output. I don't see how obj and Object2 are connected. Can anyone please explain what's happening here?
After this line...
Object2.prototype = object1;
... both Object2.prototype and object1 refer to the same object. Hence this line...
Object2.prototype.hello = function() { // ...
... assigns a new property to the object referred by object1.
I don't see how obj and Object2 are connected.
With var obj = Object.create(object1), you create an object which __proto__ property points to object1. The latter, as we established, is actually the same object Object2.prototype points to.
I.e setting Object2.prototype to an object without them both referring to the same object?
If you only want Object2.prototype to copy properties from object1, just clone an object.
I have an object that wraps some data:
function Obj1() {
var _foo = 'bar'
this.obj2 = {
'b': 'c'
}
this.method = function() {
return _foo
}
}
var obj1 = new Obj1()
Now when I call console.log(obj1); I want it to show me object obj2 content. The trick is that I need to still be able to call obj1.method and get value of _foo. How do I do that if it's even possible?
My thought was that sth like getter will be suitable, but can't figure out where and how to assign one.
As far as I understood you're trying to hide method property. To achieve this, use Object.defineProperty. Function will not be logged because enumerable property is false by default which prevents property from showing in console.log for example.
function Obj1() {
var _foo = 'bar'
this.obj2 = {
'b': 'c'
}
Object.defineProperty(this.obj2, 'method', {
value: function() {
return _foo;
}
});
return this.obj2;
}
var obj1 = new Obj1()
console.log(obj1);
console.log(obj1.method());
if i understand correctly, you can use prototype
Example
function Obj1() {
this.obj2 = {
'b': 'c'
}
}
Obj1.prototype.method = function() {
return 'bar';
}
var obj1 = new Obj1();
//prints only properties
console.log(obj1);
//prints method result
console.log(obj1.method())
Since you calling new Obj1(). The result variable var obj1 is a class object and not a function, for you to get the value of obj2 you will have to call obj1.obj2 in your console log. If you want obj1 to hold the value of obj2. Then use the following code
function Obj1() {
var obj2 = {
'b': 'c'
}
return this.obj2;
}
var obj1 = Obj1();
console.log(obj1);
This will give you the required result in the console log, but the object will no longer be a class object and will have only the value of obj2.
Sticking to your original snippet a factory looks like a good option:
function factory() {
var foo = 'bar';
var props = { b: 'c'};
var proto = {
method: function() { return foo; }
};
var obj = Object.create(proto);
Object.assign(obj, props);
return obj;
}
var obj = factory();
console.log(obj); // {b: 'c'}
console.log(obj.method()) // 'foo'
You could even pass props as an argument to get a more flexible way of spawning objects with an "unenumerable" method accessing private members.
In javascript, I have an object literal:
var objA = {
doStuff: function() {
// do objA stuff
}
}
I extend objA, and override the doStuff method:
var objB = _.extend(objA, {
doStuff: function() {
// do objB stuff
}
});
However, now when objB.doStuff() is called only objB stuff gets done.
I would like for both objA and objB stuff to be done. I tried the following:
var objB = _.extend(objA, {
doStuff: function() {
this.prototype.doStuff.call(this, arguments);
// do objB stuff
}
});
objB.__proto__ = objA;
However this doesn't work. I guess I don't understand how prototypal inheritance works when extending object literals. So, what is the right way to do this?
I would like for both objA and objB stuff to be done.
You have to call the method of objA explicitly:
var objB = _.extend({}, objA, {
doStuff: function() {
objA.doStuff.apply(this, arguments);
// do objB stuff
}
}, objA);
Note that I'm adding an empty object as first argument, so that first objA's properties are merged and then yours. For more info about how _.extend works, see the documentation.
Object Literals and Prototypal Inheritance?
Object literals currently don't provide a way to set the prototype. You can create an empty object with a specific prototype with Object.create and then merge other properties into it:
var objB = Object.create(objA);
// `merge` is a fictional function that copies properties from object to another
merge(objB, {
doStuff: function() { ... }
});
You can still only call objA's method by explicitly referencing it.
Note: This section probably has to be revised after ES6 is finalized and implement.
In ES6 you will probably be able to set the prototype via the __proto__ property name:
var objB = {
__proto__: objA,
doStuff: function() { }
};
or via Object.setPrototypeOf:
var objB = {...};
Object.setPrototypeOf(objB, objA);
Then you should be able to call objAs method via the super keyword:
var objB = {
__proto__: objA,
doStuff: function() {
super.doStuff();
}
};
Unserscore's _.extend function doesn't return a new object.
It returns the same object extended, with the new properties. So, your objA has the new doStuff function.
Instead, you may want to use _.clone and then rewrite doStuff on objB.
What you are doing in your example isn't actually inheritance, but simply creation and modification. To achieve inheritance in Javascript, it's not actually an OBJECT that you are extending, per se. It's a function. An object doesn't provide direct access to its prototype, a function does. So what you're after is likely something more like:
function ObjA() {
return this;
}
ObjA.prototype.doStuff = function() {
// do objA stuff
};
function ObjB() {
return this;
}
ObjB.prototype = new ObjA();
ObjB.prototype.doStuff = function() {
ObjA.prototype.doStuff.apply(this, arguments);
// do objB stuff
}
var objA = new ObjA(),
objB = new ObjB();