Passing Javascript object attribute to a function-Call by value - javascript

I've created a Javscript prototypal object with a range of attributes. And I need to pass some of these attributes to a function. The function processes the attributes and returns some result.
function ObjCt(id,data) {
this.id = id;
this.data = data;
}
So, I'm trying to pass the data of the chart object to a function. Im calling it as:
var obj=new ObjCt(id,data);
process(obj.id,obj.data);
I read from somewhere that passing a value in JS results in a call by value and passing an object results in a call by reference. Here I am trying to call by value, but, seems whatever processing happens in the process() function is reflected in the object obj.
I checked the variable received in the process function using typeof and it comes up as 'object' and not variable. So, what can I do to pass this data as a value?
Edit
I found a rather tiresome workaround. id is primitive and data is a JSON object. So, I tried this in the process() function
JSON.parse(JSON.stringify(data))
Apparently, all references were slashed here. I have a working implementation now, but, Id still love to see if there is an easier way for passing an attribute as a value.
Edit
Solved the problem. As per Paul's answer, tried a normal step by step cloning and another alternative using jquery extend method which goes like this
var object=$.extend(true,{},oldObject);
and passed the newly created object to the process() function.
Please refer this link: What is the most efficient way to deep clone an object in JavaScript?

In JavaScript, primitives (Number, String) are passed ByVal and Objects (including Array, Function) are passed ByRef.
Most of the time this makes no difference, however you can experience problems when using methods which modify an Object without taking into consideration you may want it elsewhere, too.
To get around this, clone your Object before passing it into such a method.
Array has the native Array.prototype.slice to clone, for Objects you need to loop over keys and recurse over the properties.
Custom function to clone, lets you extend it to do more Objects via instanceof testing
function clone(o) {
var o2 = {}, k;
if (typeof o !== 'object')
return o;
if (o instanceof Array)
return o.slice().map(clone);
if (o instanceof Date)
return new Date(o);
for (k in o)
if (Object.prototype.hasOwnProperty.call(o, k))
o2[k] = clone(o[k]);
return o2;
}
Cloning via JSON, only things which can be written in JSON are supported
function clone(o) {
return JSON.parse(JSON.stringify(o));
}
Pretending to clone by using inheritance
This will not protect foo.bar.baz = primitive, but will protect foo.bar = primitive so how good a choice it is for you depends on what the Object looks like or what is being done to it.
function pseudoclone(o) {
return Object.create(o);
}
Don't try to clone functions, it will go horribly wrong. If you need to modify them somehow, wrap them.

Are you attached to that approach only?
var Chart=function(id,data){
this.ObjCt = function () {
this.id = id;
this.data = data;
}
}
then
var obj=new Chart(id,data);
obj.ObjCt();
//process(obj.id,obj.data);

Assuming that id is primitive and data is an object:
function ObjCt(id, data){
this.id = id;
this.data = eval(data.toSource());
}
This will clone the object held in data with simple trick.

Related

Copying an immutable Array or Object

I have a couple of functions in a javascript project that accept an object as an argument and are expected to return a copy of this object with a few changes. I'm trying to make these functions immutable, but the argument can be either an Object or an Array, so I can't just use Object.assign({}, original) or {...original}.
Instead, I've come up with a couple of options:
let doSomething = function doSomething(original) {
let ret = Object.assign(Array.isArray(original) ? [] : {}, original);
//OR
let ret = Array.isArray(original) ? [...original] : {...original};
//OR
let ret = Object.assign(new (original.constructor), original);
//OR
let ret;
if(Array.isArray(original))
ret = original.slice();
else
ret = Object.assign({}, original);
//make changes
return ret;
}
Out of the four, my preference would be for the third method, just because it supports any type of object (not that I plan on using anything other than Objects or Arrays), but it feels "clever" in a bad way.
Out of the four methods, which is best for readability? Or is there another preferred way to copy any type of Object?
Options #1, #2 and #4 are doing completely the same. As for readability my vote is for #2 - shortest and clearest.
Option #3 also recreates constructor/prototype chain that is not you need in this case. It will allow to run check like copiedObj instanceof OriginalObjectClass. But it also may fail once constructor expects some arguments(and does not get them obviously). So in your case it looks rather dangerous approach than helpful.
Also I completely agree with D Lowther it would be better to extract cloning itself from your recursive function.
But I guess that you don't only want to clone some object but also process clone's nested property recursively. And this way you will also require to check if this object or array, right? So instead of cloning array separately and then cloning its members it would be easier to do that in one line with .map:
function cloneRecursively(originalItem) {
let clonedItem = {...originalItem};
clonedItem.children = (clonedItem.children || []).map(cloneRevursively);
return clonedItem;
}
You can use the constructor method instead of new (original.constructor)!
As your param can be an object or an array, you could simply write it like this:
let ret = Object.assign(original.constructor(), original)
Calling it like that, will return an empty object or array.
Be aware that if your param is not a plain JS object, using constructor would either fail or return something unexpected

Loading a javascript object from the server into an existing javascript object

I am probably not the first one doing this, but I can't find or figure out how to do it.
In my javascript I have an object with 5 properties, which are all object withg data properties and functions.
So it looks like this
function Maindata() {
var obj = this;
this.id = null;
this.profile= new Profile();
this.company= new Company();
//and more
this.getid = function(){
return obj.id;
};
}
and the profile and company object also has data and functions.
Now I get an object from the server, which is the same object, but only the data, and not the functions.
Now I want to project all of the properties of the retrieved object from the server to my JavaScript object.
I've read to use jQuery Extend, but that doesn't work for me, because it only preserves the functions on the root (Maindata) object, but not on the sub-objects.
How can I load all the data from the subobjects too?
Do I have to $extend the subobjects one by one, like this:
$.extend(true, maindata.profile, result.profile);
$.extend(true, maindata.company, result.company);
or is there another solution?
First of all, in general - you want to put all functionality on the prototype and all data on the object itself:
function Maindata() {
var obj = this;
this.id = null;
this.profile= new Profile();
this.company= new Company();
//and more
}
Maindata.prototype.getid = function() {
return this.id;
};
The prototype is assigned to every object created with Maindata as a constructor and it is shared across all Maindata instances. So it is likely more efficient and easier to reason about. It's kind of like classes in other languages.
This means you can do:
// creates an object with the given prototype without running the constructor
var o = Object.create(Maindata.prototype);
$.extend(o, result); // copy data over
// Object.assign(o, result); // with ES2015 assign syntax.
If your object is nested - then you need to do this in a nested way for subproperties. You can't get types for free since they are not encoded in the JSON. You can implement a custom serializer that does this automatically for you - some libraries like Backbone do this for you but IMO they do a pretty bad job and doing this yourself is pretty straightforward.

Javascript How to overload a method and handle keys

I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"
EDIT AGAIN
Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
ie don't return this.prototype.propertyName when own is passedHere's what I have so far:
function Dict(){
this.prototype = {};
var _keys = this.prototype.keys;
this.keys = function(own){
if(typeof own === 'undefined') { return _keys(); }
var ownKeys = [];
for(var key in _keys()){
if(this.hasOwnProperty(key)) {
ownKeys.push(key);
}
}
return ownKeys;
}
}
Will this work as follows? Is there a better or already existent way to do it?
save the overloaded keys() method to a private var
return everything as usual, unless own is something that resolves to true.
if own == true, get the usual keys and filter out those
belonging to the superclass.
On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.
Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).
Any feedback is appreciated!
EDIT
In Python, we get this:
In[2]: d = {}
In[3]: 'has_key' in d.keys()
Out[3]: False
In[7]: 'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]: d.has_key('has_key')
Out[8]: False
In[9]: d['newKey'] = 5
In[10]: d.newKey # ERROR
Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.
I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.
There seem to be multiple issues here.
You seem to want to pass variable arguments to a function:
I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.
JS function arguments are very flexible.
You can either set up names for every one of them:
function foo(arg1, arg2, map, alphaMap)
and pass values directly. This style is preferred for functions that work on a fixed set of arguments.
Or you can set up an "options" object that collects keys and values:
function foo(options)
and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.
Or you can set up an empty function signature
function foo()
and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.
In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.
It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.
This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.
So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.
The direct equivalent to a Python Dict is a plain object in JavaScript.
var dict = {};
The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.
var keys = Object.keys(dict);
To iterate the keys you can either use an imperative approach:
var i, key;
for (i = 0; i < keys.length; i++) {
key = keys[i];
doSomething(key, dict[key]);
}
or a functional one
keys.forEach(function (key) {
doSomething(key, dict[key]);
});
The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:
if ( dict.hasOwnProperty('foo') ) ...
or, if it is a pure data object with no prototype chain, you can use in as well.
if ('foo' in dict)
Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.
var key;
for (key in dict) {
if ( dict.hasOwnProperty(key) ) ...
}
Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.
I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.

Sense of options = merge({}, options) statement

In the source code of serve-static npm library I have seen the following line
options = merge({}, options)
where merge function is from utils-merge library and it has exactly the following body
exports = module.exports = function(a, b){
if (a && b) {
for (var key in b) {
a[key] = b[key];
}
}
return a;
};
What is the sense of options = merge({}, options) statement since it just joins options object with an empty object?
What is the sense of options = merge({}, options) statement since it just joins options object with an empty object?
To do exactly that. It copies all properties into a new object, where they cannot be modified anymore even if the caller of serveStatic still holds a reference to the options object he passed.
However, avoiding that the caller messes with the object is not the only reason for detaching it. If we read on, we see things like
delete options.setHeaders
options.maxage = options.maxage || options.maxAge || 0
options.root = root
so we also want to avoid messing with the object that was passed to us. Mutating your arguments is an antipattern.
merge({}, options) creates the new object which has the same attributes as source object (so it is the simplest way to clone JS object). But if you don't pass an empty object as the destination object to merge function or just skip this line, all changes on options object inside serveStatic() function will affect external object what passed to function serveStatic().
Here is the detailed explanation of this nuance of JavaScript language: https://stackoverflow.com/a/3638034/1806421

Saving/Loading a complex object structure in Javascript (Node.js)

I have been coding in javascript for some time, but am fairly new to Node. I recently undertook a project that involves a complex object structure with multiple levels of prototypical inheritance and sub objects. This structure needs to be periodically saved / loaded. Saving and loading in JSON is desirable.
The Question
Is there a more elegant way of accomplishing the task of saving/loading these complex Javascript objects than my current method (outlined below)? Is it possible to design it in such a way where the constructors can initialize themselves as if they were normal objects without being bound by all of the restoring functionality?
My Solution
The base 'class' (from which, by design, all other objects under consideration inherit protoypically) has a function which processes an 'options' argument, adding all of it's properties to the current object. All deriving objects must include an options argument as the last argument and call the processing function in their constructor.
Each object also must add it's function name to a specific property so that the correct constructor function can be called when the object needs to be rebuilt.
An unpack function takes the saved object JSON, creates a plain object with JSON.parse and then passes that object in as the 'options' argument to the object's constructor.
Each object is given a unique id and stored in a lookup table, so that a function under construction with links to other objects can point to the right ones, or create them if it needs to.
Here is a plunker which demonstrates the idea (obviously in a non-Node way).
If you don't want to load the plunker, here's an excerpt which should hopefully provide the gist of what I'm trying to do:
function BaseClass(name, locale, options){
if(name) this.name = name;
if(locale) this.locale = locale;
// If options are defined, apply them
this.processOptions(options);
// create the classList array which keeps track of
// the object's prototype chain
this._classList = [arguments.callee.name];
// Create a unique id for the object and add it to
// the lookup table
if(!this.id) this.id = numEntities++;
lookupTable[this.id] = this;
if(!this.relations) this.relations = [];
// other initialization stuff
}
BaseClass.prototype = {
processOptions: function(options) {
if(options && !options._processed){
for(var key in options){
if(options.hasOwnProperty(key)){
this[key] = options[key];
}
}
options._processed = true;
}
},
addNewRelation: function(otherObj){
this.relations.push(otherObj.id);
}
// Other functions and such for the base object
}
function DerivedClassA(name, locale, age, options){
if(age) this.age = age;
this.processOptions(options);
if(options && options.connectedObj){
// Get the sub object if it already exists
if(lookupTable[options.subObj.id]){
this.subObj = lookupTable[options.subObj.id];
}
// Otherwise, create it from the options
else {
this.subObj = new OtherDerivedClass(options.subObj);
}
}
else {
// If no options then construct as normal
this.subObj = new OtherDerivedClass();
}
// If something needs to be done before calling the super
// constructor, It's done here.
BaseClass.call(this, name, locale, options);
this._classList.push(arguments.callee.name);
}
DerivedClassA.prototype = Object.create(BaseClass.prototype);
As mentioned, this gets the job done, but I can't help but feeling like this could be much better. It seems to impose a ridiculous amount of restrictions on the inheriting 'classes' and how their constructors must behave. It makes a specific order of execution critical, and requires that each object be deeply involved and aware of the restoration process, which is far from ideal.

Categories