How to instantiate an identical JS object from an existing JS object - javascript

I have
var a = {
f1: function() {
// Do Something
},
f2: ['a','b','c'],
f3: 1234
}
I need to create something like this
var b = Object.create(a);
But b is not showing me that it contains any of the properties of a !

You can create a clone function, doing something like this:
var clone = function(obj) {
// Create a new object using the same prototype as the original object
var cloned = Object.create(obj);
// Copy each property from 'obj' to 'cloned'
for (p in obj) {
if (obj.hasOwnProperty(p)) {
cloned[p] = obj[p];
}
}
return cloned; // Return the cloned object
}
EDIT: Be careful with the first statement to create the cloned object from the original.
You have to notice that if you write var cloned = {}; as I did before, the prototypes would be different, so this solution will not work properly at 100% because if you use the instanceof operator, it will return false.
If you use just var cloned = Object.create(obj); as other answers describe, you just will obtain a cloned object with a similar prototype than the original's prototype. But you also need to copy the properties from the original object and attach them to the cloned version. That's the reason we have to use the for-loop.
Finally, if the second previous approach using Object.create does not work in your browser because it has a legacy JavaScript engine, then you have to use a small workaround as the following.
function F() {};
F.prototype = obj.prototype;
var cloned = new F();
Hope it helps! :)

Use prototype:
var b = Object.create(a.prototype);
Object.create Creates a new object with the specified prototype object and properties.
It expects the prototype for the newly created object: Object.create(proto [, propertiesObject ])
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create

Another way to do this, using JQuery is the function Jquery.extend. You can use it like this:
var b = jQuery.extend({},a);

Related

How can I modify the Object constructor

When I run the following code
var ExtendedObject = function() {
this.standard = 5;
};
Object = ExtendedObject.bind(Object);
var p = new Object();
console.dir(p.standard);
, the output is
5
as expected.
If I instead instantiate the variable p as an object literal like this:
var ExtendedObject = function() {
this.standard = 5;
};
Object = ExtendedObject.bind(Object);
var p = {};
console.dir(p.standard);
The result is
undefined
I am trying to find a way to modify the constructor of Object such that I can add some standard content to all new objects being created.
No, it is absolutely impossible to redefine how an object literal evaluates; it will always become a native object with the builtin Object.prototype, not a subclass or anything and it will also not invoke a custom constructor.
This is in fact a security feature, as it prevents JSON hijacking.
… such that I can add some standard content to all new objects being created
That's a horrible idea and will break every library you'd ever use in this environment (including all functions you'd write yourself). However, if you insist on having a common (not individual!) property on all objects, you might consider defining it on Object.prototype. Not that I would recommend it, but at least do it correctly.
You can create a class and extend it from Object.
class MyObject extends Object {
constructor() {
super();
this.standard = 5;
}
}
const obj = new MyObject();
console.log(obj);
Define the property on the prototype of Object like this:
Object.defineProperty(Object.prototype, 'standard', {
value: 5,
writable: true,
enumerable: true,
configurable: true
});
var p = {};
console.dir(p.standard);
This may be a helpful link that discuss about JavaScript objects. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects

Are JavaScript objects are one way chaining or two way?

I am trying this example from Douglas Crokford video, and as per my knowledge, changing the new object should not change the old object.
var oldObject = {
firstMethod:function(){
console.log("This is first method");
},
secondMethod:function(){
console.log("This is second method");
}
}
var newObject = Object(oldObject);
newObject.thirdMethod=function(){
console.log("thirdMethod");
}
newObject.firstMethod=function(){
console.log("I am not first method");
}
newObject.firstMethod();
oldObject.firstMethod();
Output:
I am not first method
I am not first method
But I expected,
I am not first method
This is first method
Please let me know where I am wrong.
If you call the Object constructor as a function, it performs type conversion (in this case nothing since the argument is already an object). (If you were to call it as a constructor and pass it an object, as you do there, then it just returns that object).
newObject isn't a new object, it is the same object. Any modifications to newObject are therefore also modifications to oldObject.
Possibly you want:
var newObject = {};
newObject.prototype = oldObject;
Instead of the Object() call.
TL;DR: that's (most probably) a typo in your code: it should have been written like this:
var newObject = Object.create(oldObject);
Now for explanations. This line ...
var newObject = Object(oldObject);
... does not create a new object: instead newObject variable becomes storage of the reference to the same object oldObject refers to. Here's what standard says about it:
15.2.1.1: When the Object function is called with no arguments or with one argument value, the following steps are taken:
If value is null, undefined or not supplied, create and return a new Object object exactly as if the standard built-in Object constructor had been called with the same arguments
Return ToObject(value).
9.9: The abstract operation ToObject converts its argument to a value of
type Object according to Table 14: [ ... ]
Object: The result is the input argument (no conversion).
What you probably wanted to do is use oldObject as a prototype of the new one instead. The most 'direct' way of doing it, when you already have an object, is working with __proto__ property:
var newObject = {
firstMethod: function() { console.log("I am not the firstMethod"); },
thirdMethod: function() { console.log("thirdMethod"); }
};
newObject.__proto__ = oldObject;
This feature is quite ubiquitous these days (apart from IE10-, basically all modern browsers support it). It's not a part of ES5 standard, but it probably will be of ES6.
But I guess Crockford actually meant it this way:
var newObject = Object.create(oldObject);
... as this, quoting the standard yet again, 'creates a new object with a specified prototype'.
Javascript pass object as "reference", so
var newObject = oldObject; // the old Object() just make a type cast, not necessary here
Just make newObject/oldObject reference the same object, and
newObject.firstMethod =
will just overwrite the firstMethod of oldObject too.
So to make newObject a new object, you need to do this:
var newObject = {}; //a new object
for(var k in oldObject)
{
newObject[k]= oldObject[k]; //copy old attrs
}
And then you can overwrite the methods
Yep, when you try to copy an object in javascript it simply passes it as a reference to the original, so any changes to new ones will affect the original. If you are using jQuery simply do this:
var newObject = $.extend({},oldObject);
That should solve your issue. Take a look at this for a more in-depth answer: How do I correctly clone a JavaScript object?
EDIT
Also, from the above thread a non jQuery solution:
Object.prototype.clone = function() {
if(this.cloneNode) return this.cloneNode(true);
var copy = this instanceof Array ? [] : {};
for(var attr in this) {
if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
copy[attr] = this[attr];
else if(this[attr]==this) copy[attr] = copy;
else copy[attr] = this[attr].clone();
}
return copy;
}

Copy and modify similar object for instantiation javascript

I have an object that looks like
var customObject = function() {
this.property = "value";
};
customObject.prototype = new otherObject();
customObject.prototype.property2 = function() {};
etc. - it's much bigger than this.
I can successfully instantiate the object by writing new customObject().
Now I would like to create a rather similar object, although a little different. This involves modifying certain properties and perhaps even adding or removing some. As in the above example, I would like it to be invokable by writing new customObject2().
I thought I could simply do:
var customObject2 = new customObject();
customObject2.prototype = customObject.prototype;
customObject2.property = "modified value";
etc.
However, when I try to instantiate it by doing new customObject2() I receive an error, stating that the customObject2 is not a function.
I hope I could illustrate well enough as to what pattern I desire to create. What approach should I take to create such a pattern?
If customObject is not a host object (i.e. won't give you an illegal invocation error if you try to call it differently to expected) you can apply the constructor to a different this Object;
var customObject2 = function () {
customObject.call(this); // construct as if `customObject`
// now do more stuff
this.anotherProperty = 'foo';
};
customObject2.prototype = Object.create(customObject.prototype);
// inherit prototype but keep original safe
new customObject2();
Backwards compatible Object.create
function objectWithProto(proto) {
var f;
if (Object.create) return Object.create(proto);
f = function () {};
f.prototype = proto;
return new f();
}
I think this should answer your question. Basically, the new keyword is returning an object and not a function.
Why are you not using the same formula you used the first time? For example:
var customObject2 = function(){};
customObject2.prototype = new customObject();
customObject2.property = "modified value";
new customObject2(); // works!
All properties of customObject will be inherited by the instances of customObject2 through the prototype chain.

object in prototype is inherited as reference

I want to inherit new object instance using prototype.
Test case:
var MyObj = function() {}
MyObj.prototype.objName = {}
// I want this to be a different object for each instance of MyObj
var o1 = new MyObj (),
o2 = new MyObj ();
o1.objName['a'] = 1;
o2.objName['a'] = 2;
alert(o1.objName['a']) // 2
alert(o1.objName === o2.objName) // true
This means that objects in prototype are not inherited as its copies but instead as its reference.
I know that normally you can do it like this.
var MyObj = function() {
this.objName = {}
}
var o1 = new MyObj(),
o2 = new MyObj();
alert(o1.objName === o2.objName) // false
This works fine, but in my case this is not an option. I really need to define objName outside the MyObj function.
I managed to "solve" the problem with this
MyObj.prototype.objName = function() {
if ( this._objName === undefined ) {
this._objName = {};
}
return this._objName;
}
var o1 = new MyObj(),
o2 = new MyObj();
o1.objName()['a'] = 1;
o2.objName()['a'] = 2;
alert(o1.objName()['a']) // 1
But this is not very pretty and the performance of this code is much worse.
Is there any way to solve this more elegantly ?
This means that objects in prototype are not inherited as its copies but instead as its reference.
Nothing on the prototype is copied - the whole concept of prototypical inheritance is that properties reference the shared properties of the prototype object. So if you want a property to be individual for each instance, you have to explicitly assign it to the object and shadow the prototype property; just as you're doing it with the _objName property in your code.
But this is not very pretty and the performance of this code is much worse.
If you want it pretty, move it to the constructor (or make the constructor look for something like an init method to call if exists, then you can create that init method on the prototype.
To make performance a little better, you can change the getter function to
MyObj.prototype.getObj = function() {
var obj = {};
this.getObj = function(){ return obj; }; // overwrite itself
return obj;
};
though it still has the function call overhead. For even more elegance, you can use a getter property (not supported in old browsers) that removes itself on the first access:
Object.defineProperty(MyObj.prototype, "objName", {
get: function() {
var obj = {};
Object.defineProperty(this, "objName", {
value: obj,
writable: true //?
});
return obj;
},
enumerable: true,
configurable: true
});
Now you can omit the function call parenthesis.
This means that objects in prototype are not inherited as its copies but instead as its reference.
Just to be clear. First of all in JavaScript all objects are passed by reference, not by value. Only primitives are passed by value.
Second, you're not actually "copying" or "passing" anything. When you set a prototype, you're creating a prototype's chain. It means that in your case:
var MyObj = function() {};
MyObj.prototype.objName = {} ;
var o1 = new MyObj ();
var o2 = new MyObj ();
Both o1 and o2 doesn't have any property called objName, and you can simply test it with:
console.log(Object.keys(o1)); // []
When JS see a code like o1.objName, as first thing checks if the object has this property, and if it has, use it. If not, start to looking in the prototype's chain, starting by the prototype of o1, that is MyObj.prototype: it found the properties objName, and returns it. If it didn't find it, then JS will continue to check the prototype of MyObj.prototype, and so on. So, here the point: MyObj.prototype it's an object: and you shared that object between o1 and o2. That's why the instance of objName is the same. It's exactly the same logic of having:
function objName(obj) {
return "objName" in obj ? obj.objName : O.objName;
}
var O = { objName: [] };
var foo = {};
var bar = {};
objName(foo).push(0);
objName(bar).push(1);
So, you can't put in prototype any object that is not meant to be shared across the objects creates using that prototype. I would say that shared states like that is also a bad practice that should be avoided, that's why in general prototype shouldn't have such property.
It's still not clear to me why you can't modify the constructor, but the point is: when you create the instance of your object, you have to "setup" it. Usually, calling the constructor, but any function is fine. This is made also when you want to support inheritance, and calling the "super" constructor to initialize your object.

Any Other Ideas for prototyping

I've used Douglass Crockford's Object.beget, but augmented it slightly to:
Object.spawn = function (o, spec) {
var F = function () {}, that = {}, node = {};
F.prototype = o;
that = new F();
for (node in spec) {
if (spec.hasOwnProperty(node)) {
that[node] = spec[node];
}
}
return that;
};
This way you can "beget" and augment in one fell swoop.
var fop = Object.spawn(bar, {
a: 'fast',
b: 'prototyping'
});
In English that means, "Make me a new object called 'fop' with 'bar' as its prototype, but change or add the members 'a' and 'b'.
You can even nest it the spec to prototype deeper elements, should you choose.
var fop = Object.spawn(bar, {
a: 'fast',
b: Object.spawn(quux,{
farple: 'deep'
}),
c: 'prototyping'
});
This can help avoid hopping into an object's prototype unintentionally in a long object name like:
foo.bar.quux.peanut = 'farple';
If quux is part of the prototype and not foo's own object, your change to 'peanut' will actually change the protoype, affecting all objects prototyped by foo's prototype object.
But I digress... My question is this. Because your spec can itself be another object and that object could itself have properties from it's prototype in your new object - and you may want those properties...(at least you should be aware of them before you decided to use it as a spec)...
I want to be able to grab all of the elements from all of the spec's prototype chain, except for the prototype object itself... This would flatten them into the new object.
Currently I'm using...
Object.spawn = function (o, spec) {
var F = function () {}, that = {}, node = {};
F.prototype = o;
that = new F();
for (node in spec) {
that[node] = spec[node];
}
return that;
};
I use it for every object I prototype, but because i use it so much, I'm looking to hone it down to the best possible.... I would love thoughts and suggestions...
If I've understood your question properly, you're asking how to use an approach like the one you have provided, but still be able to access prototype properties when they are overridden by the spec?
One way to get around the problem of inaccessible (overridden) prototype properties is to add them to the object along with the spec, but namespace them.
This example show how you could add the overridden to the object by prefixing it with an underscore. Put your namespacing of choice in it's place! (for example, you could use a 'super' property on the object)
Object.spawn = function (o, spec) {
var F = function () {}, that = {}, node = {};
F.prototype = o;
that = new F();
for (node in spec) {
if("undefined" !== typeof o[node]) {
that['_' + node] = o[node];
}
that[node] = spec[node];
}
return that;
};

Categories

Resources