Greetings dear community,
my goal is to spoof the screen object properties, but I can not just overwrite the properties by using:
window.screen[property] = number; or Object.defineProperty(...)
because these properties are read-only.
Therefore I wanted to kind of clone or recreate the screen object, manipulate the properties and then overwrite the whole window.screen object.
My attempt:
var clone = Object.create(Screen.prototype);
Object.assign(clone, window.screen);
console.log(clone);
The prototype is cloning well but not the properties.
After trying to get them with the Object.getOwnPropertyNames and Object.keys functions, which did not work either (example here), they have to be in the prototype.
So I tried this:
var clone = Object.create(Screen.prototype);
Object.assign(clone,Object.getPrototypeOf(window.screen));
console.log(clone);
which outputs the error "TypeError: 'get availWidth' called on an object that does not implement interface Screen."
Iterating with a for-in loop and assigning them does output the same error.
So it seems like I have to implement the interface Screen, even though I'm not sure if my plan is working after that. Perhaps there exists a simpler solution.
Other ideas:
I could assign the complete screen object as prototype (like that Object.create(screen)) and then set own properties on the object, but then the original values are still readable.
Maybe I also somehow can create an object by using Screen(...) interface?
Thanks for your help and ideas!
Seems like this is easily possible by the help of the Object.defineProperty() method, as long as the property is configurable.
var exampleProperty = 'colorDepth',
exampleValue = 55;
console.log("before:", screen[exampleProperty])
Object.defineProperty(screen, exampleProperty, {
// add descriptor properties here if desired
value: exampleValue
});
console.log("after:", screen[exampleProperty])
Related
This is my code and I am trying to change value of object in packs object. But when I type it, Javascript somehow changes all three different objects, that have nothing in common. And this is the only line that changes packs, rest should stay the same, but it's all changing with this line. How?
console.log(packs[usedPack].levels[level].bestBy) //null
console.log(defaultPack.levels[level].bestBy) //null
console.log(mainPacks[usedPack].levels[level].bestBy) //null
packs[usedPack].levels[level].bestBy = nameTyped; //this changes values in three different objects
//packs[usedPack].levels[level] = nameTyped; //if I type like this, this does change only original object, rest stays the same
console.log(packs) //nameTyped
console.log(defaultPack) //nameTyped
console.log(mainPacks) //nameTyped
Edit: It was indeed problem with referencing. I was using constructor function and this function needed to deep copy complex objects. I was checking values and I used multiple loops to copy all values from objects, but it didn't work properly. I've changed all of this to JSON.parse(JSON.stringify()), and it's working now. Thanks for help.
The issue here seems like you're assigning some object by its reference.
In javascript, if you have two objects and you assign them like
a = b;
Now whenever you will change b, a will also be changed. To avoid this we do deep clone using the spread operator
// this now does not reference to b but clones it
a = {...b}
In your code, you might be assigning some objects like this. a=b
Maybe you're assigning packs, defaultPack, and mainPacks using some same object.
Updated
#David pointed out one thing and that is if you are having some complex structure (like objects within object) and then you clone it using spread operator, the inner objects will still reference the same object.
To resolve this, for easiness you can use lodash deepclone function
const clonedeep = require('lodash/clonedeep');
const deepClonedObject = clonedeep(originalObject);
This will deep clone and even if the objects are nested they won't refer to the same object.
How come I can store an object as it's own property? Here is a simple example:
let obj = {};
obj['obj'] = obj;
This will result in having an infinite object tree: I can call obj with obj.obj.obj.obj or even with obj.obj.obj.vobj.obj.obj.obj.obj.
Is this an issue for performance? It doesn't seem to bother the browser at all.
Actually, when I look at the console in Chrome and click to expand obj's properties it says (on the tooltip of i):
Value below was evaluated just now
So they were evaluated just when I clicked to expand.
Does this mean that JavaScript too will not look at obj's property until I actually access them?
Is obj.obj just a reference to obj?
Is this an issue for performance?
No. A circular reference is just as every other reference. Every class instance has actually a circular reference:
instance.constructor.prototype.constructor.protototype
Is obj.obj just a reference to obj?
Yes.
Does this mean that JavaScript too will not look at obj's property until I actually access them?
Yes. And the console won't try to expand it as it would get caught up in an endless loop.
I would like to expand all classes of Fabric.js with few properties that should be serializable as well. I was doing it this way:
var stateProps = fabric.Object.prototype.stateProperties;
stateProps.splice(0,0,"name", "id", "creator", "dateTimeCreated");
fabric.Object.prototype.stateProperties = stateProps;
It works for the object without the problem but "stateProperties" of all inherited classes are sometimes unfortunately "initialized" for the prototypes and my new properties are not mentioned.
Is there any way to call these lines before the prototypes of the inherited classes would be initialized?
The reason inherited "classes" don't get new properties is because they're built during declaration (when Fabric is initialized). So at that point, they're using original value of fabric.Object.prototype.stateProperties.
If your goal is to include properties in serialization output, don't forget that you can always use toJSON/toObject with additional "propertiesToInclude" argument:
object.toJSON([ 'foo', 'bar' ]);
Lets say you have this object:
mainObj = {
foo1: 'bar1',
foo2: 'bar2',
foo3: 'bar3'
}
Now I want to make a close of this object by doing cloneObj = mainOb. Now we have two identical objects.
When I change the value of mainObj.foo1 = 'lolcats' after I made the clone then for some reason cloneObj.foo1 = 'lolcats'
I tested this in Chrome's console on a much more complex object. I know for certain that there's nothing in my script that would keep making the two objects sync up. I even made sure of this by creating random names for the cloneObj.
Is this behavior done on purpose or am I experiencing some sort of bug? Or am I just missing something very fundamental here?
You didn't clone the initial object when you just did cloneObj = mainOb, you are actually passing a reference to mainOb that can be accessed via the cloneObj variable name. You therefore have two variable names referencing the SAME object.
when you assign/clone object such as cloneObj = mainOb you just create another reference to the same object. Both mainOb and cloneOb points to the same object thus, a change in one is reflected on another.
Order.prototype.selectItem = function(newItem) { ...
newItem is the object I want to copy and then modify the copy without modifying the original newItem.
var newSelectedItem = newItem;
newSelectedItem.orderIndex = this.selectedItems.length + 1;
Changing the orderIndex of the copy will also change the original newItem.
Question: How do I copy and then modify the copy without modifying the original newItem.
Thanks!
Create a new object
var newSelectedItem = {};
And copy all properties from the old object into the new one
for(var prop in newItem){
if(newItem.hasOwnProperty(prop)){
newSelectedItem[prop] = newItem[prop];
}
}
Note that this solution only works for plain objects that are flat. If "newItem" is an instance of some prototype you cannot just create the new object with {} and if properties can contain mutable arrays or objects then you also need to do a recursive deep copy.
For more examples, the dojo toolkit has some functions (mixin and clone) for doing this kind of thing: http://trac.dojotoolkit.org/browser/dojo/dojo/trunk/_base/lang.js
If you're using jQuery (which I'd suggest), you can clone objects per this post:
What is the most efficient way to deep clone an object in JavaScript?
You don't necessarily need to clone the object. If all you want to do is have an object you can set properties on without altering the original, the so-called "Boodman/Crockford delegation" is far more efficient. Wishing I had published that when I first used it :) See also dojo.delegate