Object gets copied, but i want the original - javascript

I have some global vars, which I know, bad code and all.
One of these vars: MyApp.player.pet, is an object of type pet, attached to the player object. It has some properties like "xp" which is just a number.
I am passing this object to a dynamic UI class that displays information about all kinds of objects, which is why I can't use the reference to the global var inside the object. Here is how I pass it:
var listOfProperties =
[MyApp.player.pet.name,
{"xp: ": MyApp.player.pet.xp},
{"xpToNextLevel: " : MyApp.player.pet.xpToNextLevel}];
then I transfer this list of properties to a new UI object as such:
new tooltipText(listOfProperties, ..., ...)
However, when the value gets updated inside MyApp.player.pet.xp the value inside the object tooltipText doesn't change. Somehow it's passing a copy, but I want to pass a reference if those are correct terms.
I've tried searching for this but all I can find are people asking how to make copies of objects, which seems to be what I've done unintentionally but not what I want.
How can I make sure that when MyApp.player.pet.xp changes, the value inside the tooltiptext also changes?

There is some misconception in your question:
You did not create copies of your original objects.
You merely copied some of their property values, by putting them into new objects (e.g. {"xp: ": MyApp.player.pet.xp}).
If you want to change the properties of your original objects, you need to change them there, not in your newly created small objects.
So if you want a generic list of properties, you need to keep a reference to your original object (MyApp.player.pet) as well. Example:
var listOfProperties = {
obj: MyApp.player.pet,
propertyNames: ['xp', 'xpToNextLevel']
}
You can then use the property names to generically set the properties of your original object:
var propertyName = listOfProperties.propertyNames[0];
listOfProperties.obj[propertyName] = newValue;

Related

(jQuery) can't append the same object multiple times

I can understand the purpose of clone() method when appending a copy element like this:
$aObject = $('.className').clone();
$aObject.removeAttr('id');
$('#add-line').click(function() {
$('#container').append( $aObject.clone());
});
But what I don't understand is, if I get rid of the clone method, just using
$('#container').append( $aObject);
I should still be able to add multiple same object to the container, but it seems like I can only add the aObject once? can't we add same object many times on purpose just like an array of same objects?
When you assign an object to a variable in JavaScript, you aren’t actually assigning the object value stored in memory – rather a reference that points to the object’s location in memory.
So, when you declare $aObject, you have now stored a reference to a particular object. When you append it, it behaves as you would expect, appending the object that you are referencing. When you try to do the same thing again, it is referring to the same object that now already exists in the DOM and simply takes that object and re-appends it (what Scott Marcus meant when he said it acts as move).
If you clone it first, then you are referencing an entirely different object, which can be appended in addition to any objects you've already appended.

Backbone.js instance vs class variables

I'm having some confusion about instance and class variables. I made a fiddle to display something that seems inconsistent to me.
https://jsfiddle.net/njcfm4n8/1/
I'm familiar with the problem of declaring an array as a subclass property, it should be done in the initialize function, otherwise the array is shared among all instances. The fiddle demonstrates that. However, why is the number property not shared as well?
As per muistooshort and maris' comments, the array happens to work like a class property because it is a reference type. That array really is shared among the instances of your model, but this is more a quirk of javascript and not the intended way to create class variables with Backbone.
An integer on the other hand is a primitive type, along with booleans and strings, and javascript does not pass references to these types but copies them instead.
Arrays, objects, and functions are reference types, while integers, booleans, null and undefined are value types. You can learn more about it here: http://docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm
If you want to make use of class properties, then this section of the Backbone docs is relevant: http://backbonejs.org/#Model-extend
extendBackbone.Model.extend(properties, [classProperties])
To create a Model class of your own, you extend Backbone.Model and provide instance properties, as well as optional classProperties to be attached directly to the constructor function.
I've forked your jsfiddle here https://jsfiddle.net/zn6bu4uf/3/ with this code:
var myModel = Backbone.Model.extend({}, {foo: 0})
console.log(myModel.foo); // 0
myModel.foo++;
console.log(myModel.foo); // 1
var test1 = new myModel();
var test2 = new myModel();
test1.constructor.foo++;
test1.constructor.foo++;
test2.constructor.foo++;
console.log(test1.constructor.foo) // 4
console.log(test2.constructor.foo) // 4
Backbone add your properties (n and arr) to myModel prototype.
Because of that all myModel objects has n and arr in their __proto__ and can access to them.
Array shared among objects because there is no assignment to place where array stored. Push mutates array itself.
But increment actually creating new value and then assigning it to object.
From spec:
test1.n++ will actually do this
get property n from object test1 (if its not there search in test1.__proto__ ... ) and save it virtual variable old_val.
set virtual variable new_val to old_val + 1
set value of property n in object "test1" to value of new_val
return old_val
By spec step 3 not checking initial location of property n. It will add new property to test1.
spec
post increment evaluation
get and put value to object

Javascript is changing variable that needs only to be referenced

I'm pulling some data from a reference object changing it around for what I need, but for some reason my code is also changing the object i'm referencing..
var obj = {name:"list of things", list:[{name:"thing", 1},{name:"other thing", 2}]};
function doStuff () {
var ref = obj;
for(var p=0;p<ref.list.length;p++){
ref.list.splice(1,1);
}
return ref;
}
For some reason where I'm using this structure in my code, its changing 'obj' as well as 'ref'. can't seem to figure it out
The obj in your example is not an object, it is a reference to an object that lives somewhere in memory. This is why when you do ref=obj, you get another reference to the same object, so changing the object ref references is the same as changing the object obj references.
What you want to do is clone your object, so you end up with two different objects. There are some good answers regarding cloning on StackOverflow and the whole web for that matter. Feel free to use any of those.
JavaScript assignes by reference. You would need to do a deep copy in order to clone an object.
See: http://webdevwonders.com/deep-copy-javascript-objects/

How to copy or TypeCast a javascript object to a variable with the base class

I have a Javascript Object (It's a dojo/stateful object), that I created from a data structure. I want to convert that stateful object back to a standard hash object.
a = {test: "a test"};
b = new stateful(a);
new_a = new object(a);
The reason for this is because I have a function that needs to be passed an object with the base object class. Passing it a stateful object doesn't work, even though the data structures are the same.
I've found that doing a
new_a = b;
new_a.__proto__ = new_a.__proto__.__proto__
will do what I want in the version of Chrome I'm using, but I'm guessing this is a really bad way of doing it.
You could create watches for each property on the original object. This will keep the original object in sync with changes to the stateful object.
This example extends the dojo/Stateful object to keep the original and adds the watches to update the original object.
http://jsfiddle.net/cswing/YJHtH/

What is the use of creating a class in javascript, if I can insert any attritube to an object any time

Consider the below code.
I created an empty object. And am adding var1,var2,var3 without declaring them.
var har = new Object();
har.var1 = "Var1";
har.var2 = "Var1";
har.var3 = "Var1";
alert( har.var1 );
If I can do this, then why do I need to create a Class and fix the attributes when I can introduce new attributes anytime?
Why would you even need to use objects in the first place? Non-object-oriented languages are already Turing-complete, so everything you can accomplish with objects you can also do without them.
What you're showing in your example is not really an object, but just a dictionary. In cases like this, where you only need to keep several related properties together, anonymous unprototyped objects like the one you're using are the de-facto standard approach (though it is customary to initialize them with the shorthand syntax, e.g. var har = {}). It is an object, since it uses the object data structure, but it is not object-oriented.
Actual objects, in contrast, not only define data, but also the operations that you can perform on that data. Objects have not only properties, but also methods which work on these properties. These properties are usually defined in the object prototype (which you're calling "class", but Javascript is not a class-based language, but a prototype-based one). All methods defined in the prototype are shared between all instances of that prototype.
function Counter() {
this.counter = 0;
}
Counter.prototype.increment = function() {
this.counter++;
alert(this.counter);
}
var c1 = new Counter();
var c2 = new Counter();
c1.increment(); // alerts 1
c1.increment(); // alerts 2
c2.increment(); // independent from c1: alerts 1 again
Each instance is still a dictionary, as in your example (and you can even still add more properties to them, they are not "fixed" by having a constructor and prototype), but now it can also perform tasks on its properties. This can be done your way as well:
c1 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
c2 = {
counter: 0,
increment: function() {
this.counter++;
alert(this.counter);
}
}
You can see, however, that if you need two counters, without using prototypes you will need to duplicate your entire object definition. This will be cumbersome to write and maintain, and each increment function will be defined separately, thus it will also waste memory.
That said, in cases where you need an object that you know you'll only ever need one instance of, it makes no sense to define a constructor and a prototype for it. Such objects are usually regarded as namespaces instead of actual objects.
Appendix: Dictionaries vs Objects
A dictionary is a data structure which holds named elements. Besides "dictionary", they are also called associative arrays or hashmaps. Objects in Javascript are implemented as dictionaries — each property is a named element in the dictionary. In addition to a plain dictionary, objects also have a prototype, which is kind-of like a parent object — when you look up a named element in the dictionary and it is not there, it is automatically searched for in the prototype as well. This way, default properties and methods are defined only once in the prototype, and do not need to be copied into each instance. (The prototype of an object is often visible as the instance.__proto__ property, though this is non-standard and deprecated even in browsers that support it; the actual prototype is defined as an internal, non-accessible property by the standard)
So, Javascript objects are actually dictionaries. When you want to use a plain dictionary to store some related properties together, there is no separate syntax in Javascript to create a dictionary that is not an object, so you create an instance of the base Object type to hold your dictionary (it does not matter if you do var dict = new Object or var dict = {}, the result is the same); thus, dictionaries that you use in your code are also objects.

Categories

Resources