var myObject = new Object();
var myObjectCopy = myObject;
myObject.Name = 'alav';
// logs Name alav on both variable
console.log(myObject, myObjectCopy);
myObject = null;
// logs myObject as null and myObjectCopy still has name 'alav' -> bcoz of reference copy
console.log(myObject, myObjectCopy);
The same behavior is not getting replicated below.
var objA = {property: 'value'};
var pointer1 = objA;
// update the objA.property, and all references (pointer1 & pointer2) are updated
objA.property = pointer1.property;
objA.property= null;
// logs 'null null' because objA, pointer1 all reference the same object
console.log(objA.property, pointer1.property);
Why the above reference copy behavior is not applicable to inner properties(property here) of an object?
objA.property = pointer1.property; -> aren't reference COPY?
In case one you were setting reference to null therefore no change in actual object
myObject = null;// setting reference to null object , but no change in actual object
In second case you are making changes into the object(changing state of object)
by setting property to null
objA.property = null;
hence in every reference , value of property will be null
Related
I have this piece of code:
var MyConstructor = function(){};
var MyObject = new MyConstructor();
What I noticed is MyObject.constructor is not pointing to MyConstructor. So what is the standard way of accessing the constructor of an object from the object itself?
I need this to access constructor's prototype properties like MyConstructor.prototype = {mykey : "value"}. I can access mykey this way: MyConstructor.prototype.mykey but MyObject.constructor.prototype.mykey is not defined.
Here is the complete code and their output using jsconsole.com:
var MyConstructor = function(){};
MyConstructor.prototype = {mykey : "value"};
var MyObject = new MyConstructor();
MyObject.mykey; // output: "value"
MyConstructor.prototype.mykey; // output: "value"
MyObject.constructor.prototype.mykey; // output: undefined
MyObject.constructor === MyConstructor; // output: false
MyObject.constructor.prototype.mykey === "value"; // output: false
This happens because you change the prototype property of MyConstructor. That means that MyObject is created from that object and does not get the constructor property that the original prototype object had. So in your test case, MyObject.constructor === Object, since that is the constructor that is used for the object literal {mykey: "value"}.
To avoid this behaviour, don't assign a new object to the prototype property, but mutate the existing one:
var MyConstructor = function(){};
MyConstructor.prototype.mykey = "value";
var MyObject = new MyConstructor();
console.log(
MyObject.mykey, // output: "value"
MyConstructor.prototype.mykey, // output: "value"
MyObject.constructor.prototype.mykey, // output: "value"
MyObject.constructor === MyConstructor, // output: true
MyObject.constructor.prototype.mykey === "value", // output: true
);
Object.getPrototypeOf(MyObject).mykey gets the prototype directly from MyObject.
Mozilla developer link
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.
var triangle = { a: 1, b: 2, c: 3 };
function ColoredTriangle() {
this.color = 'red';
}
ColoredTriangle.prototype = triangle;
var obj = new ColoredTriangle();
console.log(obj.constructor.name, obj);
//result: Object ColoredTriangle {color: "red"}
I use chrome browser.
Here, var obj = new ColoredTriangle(); using this, you are creating a new object of function ColoredTriangle().
Hence, in your console result, ColoredTriangle {color: "red"} shows the content of the obj that you are printing. You can see it also shows function properties.
obj is instance of the constructor ColoredTriangle. So the obj.constructor will be the function object which is ColoredTriangle. .name will get the name of that function.
According to MDN about Function.prototype.name
A Function object's read-only name property indicates the function's name as specified when it was created, or "anonymous" for functions created anonymously
See the example below.
Note: The name property is only specific for the function objects. I will not work for other datatypes.
function foo(){}
let instance = new foo();
console.log(instance.constructor); //function foo(){}
console.log(foo.name) //foo
The javascript bind method returns a bound object however the returned object contains none of properties of the original object.
In case the property is set on the prototype object, I can use Object.setPrototypeOf to restore all the properties, however I can't figure out how to do the same for properties on the function itself.
var obj = function(){/*some code logic */}
obj.a = 1;
var boundedObj = obj.bind(obj);
boundedObj.a; //returns undefined
var boundedObj2 = Number.bind(Number);
boundedObj2.EPSILON// returns undefined
Object.setPrototypeOf(boundedObject2, Number);
boundedObj2.EPSILON // returns the epislon value
You can use Object.assign() to copy all the enumerable, own properties to the bound function.
var obj = function(){/*some code logic */}
obj.a = 1;
var boundedObj = obj.bind(obj);
Object.assign(boundedObj, obj)
console.log(boundedObj.a);
I have a problem I can't solved because I can't explain this behaviour :
var A = function(value) {
this.prop = value;
};
A.prototype = {
prop: 0
};
var a = new A(1);
var b = new A(2);
console.log(a.prop);
console.log(b.prop);
output :
1
2
But, with this code (almost the same) :
var A = function(value) {
this.prop.value = value;
};
A.prototype = {
prop: {
value: 0
}
};
var a = new A(1);
var b = new A(2);
console.log(a.prop.value);
console.log(b.prop.value);
I have this output :
2
2
Can anybody explain me this ?
Thanks...
EDIT :
Here's a solution :
var A = function(value) {
this.prop = {};
this.prop.value = value;
};
A.prototype = {
};
var a = new A(1);
var b = new A(2);
console.log(a.prop.value);
console.log(b.prop.value);
In example 1, this.prop is a primitive type, which is referenced by value and thus not shared between instances.
In example 2, this.prop is an Object whose reference is initialized from the prototype from a single object, so this single object is shared by all instances.
In the last "example" solution, you create a new object with = {}, so all instances now have their own object.
More details about primitive types : Primitive value vs Reference value
prototype is created only once and it's only a simple object whose childs are attached for all instances of a function it belongs to.
So it's basically the same as if you write:
var obj = { value: 0 };
var a = {}, b = {};
a.obj = obj;
b.obj = obj;
obj.value = 2;
as you can see both a.obj and b.obj references to the same obj and both a.obj.value and b.obj.value will be 2 in this example
This is happening because in JS, objects are passed by reference, while primitives are not.
Since the prototype is shared between the 2 instances, modifying a object on it will update all instances.
Think of a prototype property as a property shared amongst all instances.
Yet you can override it on each instance, that 's what you do in the first example.
Once overriden in each instance, you do not access any more to the prototype property with obj.prop, which now refers to the instance property. You would need to use obj.prototype.prop to read it again, but this syntax is illegal : you can use obj.__proto__.prop (non standard) or Object.getPrototypeOf(obj).prop (EcmaScript 5) to do so.
In the second instance, you do not change the property in the constructor : rather you change a property of this property. So both constructor access to the very same object, then change one of its property value, so the last to set it will 'win'. Here the prototype property is not overriden ('hidden') by the instance property and accessing obj.prop in fact access 'obj.prototype.prop'.