Difference between Object.create(foo) and new Object(foo)? - javascript

Why is that this code:
var foo = {one: 1, two: 2};
var bar = new Object( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //100
results in bar.one & foo.one being both 100, while
var foo = {one: 1, two: 2};
var bar = Object.create( foo );
bar.three = 3;
bar.one = 100;
document.write(bar.one); //100
document.write(foo.one); //1
only affects bar.one..
My first intuition is that since in the first piece of code we are assigning a foo reference to bar, then it means the change will also apply to foo, while on the second code, it probably 'inherits' from foo, and therefore the change on bar's 'subclass' attribute won;t apply to its 'superclass' (prototype)..
Can somebody please confirm that my assumption is at least on the right track? Would absolutely appreciate any answers. Thanks in advance.

The line:
var bar = new Object( foo );
In your first snippet, it doesn't do anything -you are right with your assumption-, it will simply return a reference to the same object passed to the Object constructor.
That's the behavior when you pass a native object to the Object constructor in a new expression (new Object(value)), if you pass a host object, the results are implementation dependent.
If you don't pass a value (or you explicitly pass the primitives undefined or null) a new object that inherits from Object.prototype will be created.
Otherwise, if you pass any of the remaining primitives (as a Number, String or a Boolean value), a primitive wrapper object will be created (basically "primitive-to-object" type conversion), for example.
var s = new String("foo"); // a string object wrapper
typeof s; // "object"
s.valueOf(); // "foo"
See this question about primitives and objects: How is a Javascript string not an object?
In your second snippet, the line:
var bar = Object.create( foo );
Creates a new object, that inherits from foo, and since it's a different object, when you assign the properties:
bar.three = 3;
bar.one = 100;
Those will be created physically on that separated instance, as you can see, the bar.one property shadows the value contained in foo.
The object referenced by bar, in fact will contain two own properties (one and three, but since it inherits from foo, the property named two is resolvable through the prototype chain, for example:
bar.hasOwnProperty('one'); // true, the property is "own"
bar.hasOwnProperty('two'); // false, the property is "inherited" from foo
bar.two; // 2, is accessible
Basically, the prototype chain of bar looks like this:
-----------------
========> | Object.prototype| ==> null
| -----------------
|-------------| [[Prototype]] |---------|
| one: 100 | ====================> | one: 1 | (shadowed)
| three: 3 | | two: 2 |
|-------------| |---------|
(== line denotes the prototype chain)

new Object and Object.create do completely different things, despite their similar sounding names.
new Object(), with no argument, is equivalent to an empty object literal {}, which you should always use instead. With an argument, new Object(obj) simply returns the argument.
Object.create(obj) helps untangle JavaScript's messed up prototypal inheritance. Reading this article by Douglas Crockford will help with that. Basically, it creates a new object that inherits from obj. So if you have
var obj1 = {x: 1}, obj2 = Object.create(obj1);
obj1.x; // 1
obj2.x; // 1
obj2.x = 42;
obj1.x; // 1
obj1.x = 10;
obj2.x; // 10, since obj2 inherits from obj1, changing obj1's properties
// changes obj2, but not the other way around.

Related

Use Object.freeze(Class.prototype) while remaining able to override prototype properties [duplicate]

Why can't I assign new properties to non-frozen object, which has frozen prototype:
Working without Object.freeze:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
Above code works as expected, but I want to make sure that defaults won't be accidentally changed. So I want to freeze my defaults object:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
//TypeError: Cannot assign to read only property 'sections' of #<Object>
specificObject.sections = {};
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
What I don't get is why can't I assign to specificObject if its prototype is frozen?
//EDIT:
Notice that specific object is not frozen:
'use strict'
//This object will be prototype of next objects
var protoObj = {a: 1, o: {}};
Object.freeze(protoObj);
console.log(Object.isFrozen(protoObj)); //true
var n = Object.create(protoObj);
console.log(Object.isFrozen(n)); //false
What I don't get is why can't I assign to specificObject if its prototype is frozen?
Because property attributes are inherited. Yes, it's odd.
If you freeze an object, it will set the [[writable]] attribute of all data properties to false.
If you assign to an object property, but that property does not exist on the object, it will go and look it up on the prototype - it might be defined as setter there. When this lookup will return and say that there is a property of that name but it is non-writable, your assignment will fail (and throw in strict mode).
What can you do against this?
Use Object.defineProperty instead of assignment, it doesn't check the prototype
or similarly, use the second parameter of Object.create to create the own property
freeze the defaults only after you've assigned to specificObject.
my understanding is that specificObject.sections is pointing to its' prototype which is defaults and it is frozen object. You define a new object {} but you try to assign it to defaults.sections. SpecificObject.sections is pointing exactly there.
If you create new ownProperty on specificObject it will work:
'use strict'
//This object will be prototype of next objects
var defaults = {
name: 'def name',
sections: {
1: {
secName: 'def sec name'
}
}
};
//!!!!!!!!!!!!
Object.freeze(defaults);
//So we have an empty object with prototype set to our default object.
var specificObject = Object.create(defaults);
// this will create new property
Object.defineProperty(specificObject, 'sections',{
enumerable: true,
writable: true,
configurable: true,
value: {}
});
console.log(specificObject.hasOwnProperty('sections')); //true
specificObject.sections['1'] = Object.create(defaults.sections['1']);
explanation:
if you try to access obj.prop = val then javascript looks into obj's own properties, if not found then it looks into obj's prototype own properties. if found there then it /tries to assign val to/ lookup that property. if not found there then it tries to look into obj's prototype's prototype and so on. If prop is not found in the prototype tree then it creates new own property on obj and assigns val.
Therefore if prop is find on prototype and it is frozen you will get type error. Hope it brings some light.:)
EDIT:
as correctly pointed out by #KubaWyrostek specificObj.sections = {} will create new own property of specific Object, does not assign new value to the prototype's property, but it probably does the lookup for the property to check the writability, in that case it will run into frozen object. I didn't know about this before.

Object literal constructor

I am looking for a way to modify an object that was defined by a literal without passing it into another function.
example:
let o = {a:1,b:2}
console.log(o.a===3)
i thought when i define an object using a literal the the Object constructor would be called, so i did override Object.prototype.constructor but it only gets called when i do new Object({a:1,b:2})
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy or using o.a=3 or with keyword, where o is defined using an object literal?
Just do o.a=3; and console log o:
let o = {a:1,b:2};
o.a=3;
console.log(o);
Currently you are doing o.a===3 which will return Boolean value instead of overwriting the value of property a.
You also cannot do o.a=3 inside console.log() because o.a=3 will return the assigned value which is 3 but it will still change the property a of o to 3.
let o = {
a: 1,
b: 2
};
//won't print o but changes o.a to 3
console.log(o.a = 3);
It's simply not possible.
There is no constructor of an object literal.
You can create objects in different ways:
via an object literal or
via a constructor function or
via Object.create
Also, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy?
o.a = 3;
I am looking for a way to modify an object that was defined by a literal without passing it into another function.
Thats impossible, cause if it would be possible you could break every piece of javascript. And that would be terrible.
Oh wait, this is JS...
with({ get o() { return { a: 3 }; }, set o(v) {} }) {
o = {a:1,b:2};
console.log(o.a===3) // true
}
What you want to achieve could be done if o.a holds a reference to the variable a - which unfortunately only works the way you'd like for variables that are passed by reference. Primitive types like String, Number and Boolean though, are passed by value.
Check the examples below:
var a = 1;
var o = { a: a };
a = 2;
console.log(o.a, a);
It also doesn't help to use an Object constructor like new Number() because that does return a reference to an object (which is passed by reference as you'd need), but assigning a new value to it reading the value still returns a primitive (which is, again, passed by value):
var a = new Number(1);
var o = { a: a.valueOf() };
a = Number(2);
console.log(o.a, a);
If you pass something that is naturally passed by reference, your expectation is fulfilled:
var a = [ 1 ]
var o = { a: a }
a[0] = 2
console.log(o.a[0])

Javascript "new" keyword making references to "class" properties

I have a javascript "class", that I instanciate several times.
My issue is that modifying properties from the instances does actually modify those properties of the "class", so further instances are not initialized in the way I'd like.
Here is a simplified snippet of what happens, the original code is using BackboneJS but this is enough to illustrate my case:
var foo = function() {
this.defaults.id = 1;
};
// This is my property
foo.prototype.defaults = {
id: 0,
};
console.log( foo.prototype.defaults ); // => {id: 0}
var bar = new foo();
console.log( foo.prototype.defaults ); // => {id: 1}
I thought that the "new" keyword would make a brand new object but it seems that it just makes a reference to the prototype properties.
The best option I came with is to clone all properties from inside the constructor...
Do anyone have a clean way to achieve a clean "Class Property" behavior ?
Many thanks in advance,
Romain.
Edit: It does not work from the SO snippet... just copy/paste it to your console if you want.
The prototype is shared among all objects of this type. A new copy is not made. The usual way to initialize properties that are to be unique to this instance is to initialize them directly in the constructor:
this.property = "foo";
This will override any property of the same name in the prototype and will be unique per instance.
In general, the prototype is not used for data properties because they are shared among all instances. If you want to initialize an object with a default set of data properties, the "best practice" for that is to assign a default set of properties into the object instance and then set any overrides. You can't just assign a default object because objects are assigned by pointer, not by copy so all objects would still be pointing at the same object (the same issue you have when using the prototype).
You could initialize your object with a set of defaults like this:
var foo = function() {
this.defaults = {};
// copy default properties
for (var prop in foo.defaults) {
this.defaults[prop] = foo.defaults[prop];
}
this.defaults.id = 1;
};
// defaults (not on the prototype)
foo.defaults = {
id: 0,
something: "whatever",
line: 22
};
Though, in practice, it is usually easier to just code in the defaults like this:
var foo = function() {
this.options = {
id: 1,
something: "whatever",
line: 22
};
};

javascript object property references

Can someone give the best explanation of what is going on here:
var o = {
name: "jack"
};
var z = {
name: o.name
};
o = {};
alert(z.name); // expected undefined, shows "jack" instead
Are object properties just references? Destroying the object o doesn't seem to destroy the referenced object (in this case the string "jack"). Or, is it the case that the "jack" referenced by o.name is actually destroyed but that z.name created a copy of o.name?
Best
// consider this too
var o = {
foo: function () {
return "hello";
}
};
var z = {
m: o.foo
};
o = {};
alert(z.m()); // hello is displayed
You might find this more interesting.
var o = {
name: "Jack"
};
var z = {
name: o
};
//Above assignment of 'o' to z.name will create a new alias to object 'o'.
//So both 'o' and 'z.name' point to same object.
//When you change value inside 'o' it will still reflect in 'z.name'
//because both point to same object
o.name="Jill";
console.log(z.name.name); // Logs : Jill and not Jack.
// Now, here you are actually assigning a new object to 'o'.
// This means now 'o' refers to a new object. But this will no way affect
// the 'z.name' reference, it still points to same object.
o = { name : "Joe"};
console.log(z.name.name); // Logs : Jill again and not Joe
Strings are copied by value, not reference.
Even if that wasn't the cause, objects are only handled by reference so overwriting o with a reference to a new object wouldn't change any references to the old object.
Are object properties just references?
Yes and No.
They are not references in the meaning of "live updating", when you change (or delete) o.name then z.name won't be altered.
They are references in the meaning of binding some arbitrary value (with a property name) to an object. These values will exist on their own, forgotten (deleted from memory) only when no one does have a handle on them any more.
You might be interested in the overview of Objects in the EcmaScript specification.
z.name created a copy of o.name?
Yes. JavaScript differentiates between objects (with changeable properties) and primitive values (which are immutable). All of these are copied by value - there is no call-by / assign-by reference in JS - and so strictly speaking both z.name and o.name reference two different values. However the object values are so-called reference values which reference the same property-value structures in memory whenever they are copied.

Javascript and function prototype assignment

I've always assumed that the prototype of a function was shared among all the objects, in a sense by reference. So if you change the value of a property of the prototype, all objects that share that prototype have the values change for them as well. So for instance below it seems that instead of the property bar being shared between all objects, it is copied. Is this right? Are the properties of the prototype of the constructor simply copied to all the class objects as they are created, or are they shared by linkage?
function foo()
{
this.bar = 1;
}
function derived() { }
derived.prototype = new foo()
object1 = new derived()
object2 = new derived()
object1.bar = 2;
//but notice if I had said here derived.prototype.bar = 3, object1.bar would still equal 2 but object2.bar would equal 3
alert(object2.bar) // this prints 1;
When you assign object1.bar = 2, you are creating an own property on object1, this property exist only in that object instance, and it has nothing to do with its prototype.
This property on object1 will shadow the value of the one existing on derived.prototype, this means that when you lookup object1.bar, it will find a value directly existing on that object.
On the other side, if you lookup object2.bar, this object doesn't have an own bar property, so the property lookup will search on the object this one inherits from (derived.prototype) and it will find the value 1.
Your object structure looks something like this:
object1
--------
| bar: 2 | -----------------
-------- | derived.prototype
| ----------
|------> | bar: 1 | -- foo.prototype
object2 (no own properties)| ---------- | ------------------
-------- | -> | constructor: foo |
| | ----------------- ------------------
-------- |
v
------------------
| Object.prototype |
------------------
|
v
null
Where the ---> lines denote the internal [[Prototype]] link that expresses inheritance.
For example, you have code:
function Animal() {
}
Animal.prototype.name="animal";
function Dog() {
}
Dog.prototype = new Animal
Dog.prototype.constructor=Dog;
Dog.prototype.name="dog";
object1 = new Animal();
object2 = new Dog();
As a result you have two object instances, that looked as (you can check this for example in Chrome devtools or FF firebug or...):
object1:
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: Object (is ref into an Object.prototype object)
object2:
__proto__: (is ref into an Dog.prototype object)
constructor: function Dog()
name: "dog"
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: (is ref into an Object.prototype object)
When you run next code (for example):
alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "dog"
What happened? 1) Javascript looked for property name in object instance (in object1 or object2). 2) When not found, it looked up in object instance proto property (that is same as prototype of class function). 3) When not founct it looked in proto of proto and next and next while not found name property and others proto found. If as result of search property is found, then value is returned, if not found, then undefined returned.
What happened if you execute next code:
object2.name = "doggy";
As a result you have for object2:
object2:
name: "doggy"
__proto__: (is ref into an Dog.prototype object)
constructor: function Dog()
name: "dog"
__proto__: (is ref into an Animal.prototype object)
constructor: function Animal()
name: "animal"
__proto__: (is ref into an Object.prototype object)
Property is assigned directly into instance object, but prototype object remains unchanged. And when you execute:
alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "doggy"
When you need to create|change shared property of class, you can use one from next algoritms:
1)
Animal.prototype.secondName="aaa";
alert(object1.secondName); // displayed "aaa"
alert(object2.secondName); // displayed "aaa"
Animal.prototype.secondName="bbb";
alert(object1.secondName); // displayed "bbb"
alert(object2.secondName); // displayed "bbb"
// but
Animal.prototype.secondName="ccc";
object1.secondName="ddd";
alert(object1.secondName); // displayed "ccc"
alert(object2.secondName); // displayed "ddd"
2)
Create property of type object in prototype of function class and assign values to properties of this object.
Animal.prototype.propObject={thirdName:"zzz"};
alert(object1.propObject.thirdName); // displayed "zzz"
alert(object2.propObject.thirdName); // displayed "zzz"
Animal.prototype.propObject.thirdName="yyy";
alert(object1.propObject.thirdName); // displayed "yyy"
alert(object2.propObject.thirdName); // displayed "yyy"
object1.propObject.thirdName="xxx";
alert(object1.propObject.thirdName); // displayed "xxx"
alert(object2.propObject.thirdName); // displayed "xxx"
object2.propObject.thirdName="www";
alert(object1.propObject.thirdName); // displayed "www"
alert(object2.propObject.thirdName); // displayed "www"

Categories