My Query:
What is the most efficient way to reference nested JavaScript objects? I have found a couple so far, and am wondering which is the most efficient, and if there are any others which are better than those which I list here. The problem involves usage of a root object, similarly to that which many JavaScript frameworks use. The root object is compulsory. Please do not post answers which do not use a root object.
Note that this is specifically intended for root/sub-root objects which have long names - referencing a.b would be useless, whilst referencing abcdefghijklm.nopqrstuvwxyz would be extremely useful.
EDIT:
Just to clarify a couple of things:
Via efficiency I mean firstly code length (which could in turn affect performance, but that is slightly less important). I am concerned about code length partially because of file size - yes, I would be minifying it afterwards - but also due to readability for anyone viewing my original code (including myself). Performance is also slightly important, I don't want long workarounds which would slow down execution.
The referencing would be mostly for commonly used sub-objects, NOT EVERY SINGLE ONE. I state (in method 1) that many global variables would need to be created - due to the fact that I was assuming that all of the first-level sub-objects would be commonly used.
Objects to be referenced:
The object foo contains the various sub-objects bar, baz and qux, each of which contain various other objects.
var foo = {
bar: {
bar: {},
baz: {},
qux: {}
},
baz: {
bar: {},
baz: {},
qux: {}
},
qux: {
bar: {},
baz: {},
qux: {}
}
};
Method 1 - Reference Variables:
The first method involves creating a variable for each of the sub-objects.
var bar = foo.bar;
var baz = foo.baz;
var qux = foo.quz;
foo.bar.baz could then be referenced simply via bar.baz, and foo.qux.qux via qux.qux.
Advantages:
Reference variables can be very concise - a single character is the minimum possible length.
Disadvantages:
If there are many sub-objects to be referenced, this would increase the global variable count. This is likely to cause conflicts, cross-script and otherwise - especially using single-character variable names.
A new reference variable needs to be created for every nested object. Not only is this inconvenient, but it also requires the programmer to remember to create each variable after amending the object. Conversely, if a sub-object is removed and the programmer forgets to remove the reference variable also, then the code becomes messy with useless global variables cluttering it up.
Method 2 - Reference Function:
The second method involves creating a function which returns a sub-object, depending on a couple of parameters.
function ref(a, b) {
//Ensure that the first parameter is passed:
if (!a) {
return false;
}
return foo.a.b;
};
foo.bar.baz could then be referenced via ref("bar", "baz"), and foo.qux,qux via ref("qux", "qux").
Advantages:
Works for all first-level sub-objects, without repetitive and messy separate variable defining.
Disadvantages:
Only really useful for shortening the root object - if the root object is named a then using the reference function would actually lengthen the code.
Let's say we have a graphic control object, that is an instance of a GraphicObject Class (function).
Let's say one instance looks like :
grControl = {
visual : {
boundingBox : { x : , y : , width: , height : ... },
...
},
action : {
...
}
};
The right way to create shortcuts is either :
• to cache locally the appropriate object in a var in a function that will use it :
function drawBBox (someGraphicControl) {
var bbox = someGraphicControl.visual.boundingBox;
// maybe you want also to cache sub-properties :
var width = bbox.width;
...
}
• to define, on the prototype, a getter and/or a setter that will provide an access to the nested property :
// read-only example
Object.defineProperty(GraphicControl.prototype, 'width',
{ get : function() {
return this.visual.boundingBox.width },
enumerable : true};
// read-write example
Object.defineProperty(GraphicControl.prototype, 'width',
{ get : function() {
return this.visual.boundingBox.width },
set : function(val) {
this.visual.boundingBox.width = val ; },
},
enumerable : true};
this way you can use :
grObject.width
and exactly refer to :
grObject.visual.boundingBox.width
The usual practice in javascript depends upon the circumstances:
1) One-time access to that object in a particular function. If you're just making a one time access to a deeply nested reference, you just spell out the reference with all the intervening names:
var data = foo.baz.quz.prop1;
2) Multiple-accesses to a particular nested object. If there are multiple references to a particular deeply nested object, then you create a temporary local variable that points to the common object and then reference from that within the local function.
function getDeepData() {
var obj = foo.baz.quz;
var prop1 = obj.prop1;
var prop2 = obj.prop2;
var prop2 = obj.prop3;
// code that uses prop1, prop2 and prop3 here
}
3) Iterating properties who's names are not known in advance. Since you don't know the property names in advance, this is done by iterating one level at a time (sometimes recursively) and just keeping the parent object in a local variable.
If you find yourself making lots of deeply nested one-time references all over your code, then you probably want to revisit the structure of your code or data because that can usually be avoided.
Related
Consider a function that acts on one element of complex object I'm passing around. I can write it as:
function foo(object) {
bar(object.item)
}
or
function foo(item) {
bar(item);
}
If I have the option, is there any performance benefit to passing just the single element of the object to a function vs passing the whole object and pulling out the pieces I need?
I.e., is it more efficient to call:
foo(object);
and pass along the entire object let foo deal with, or
foo(object.item);
which only passes the single item?
Update: It looks like the terminology I could not find until the comments arrived is whether Javascript is pass-by-reference or pass-by-value.
As objects are passed by reference in Javascript (with some important caveats), it should make no difference how big the object I'm passing is.
Interesting reading:
https://medium.freecodecamp.org/understanding-by-reference-vs-by-value-d49139beb1c4
Object property access is a little bit more expensive than plain value access. (warning, the following snippet will block your browser for a bit, depending on your computer's specs:)
(() => {
const obj = { foo: 'bar' };
const t0 = performance.now();
for (let i = 0; i < 1e9; i++) {
obj.foo;
}
const t1 = performance.now();
const { foo } = obj;
for (let i = 0; i < 1e9; i++) {
foo;
}
const t2 = performance.now();
console.log('Object property access: ' + (t1 - t0));
console.log('Variable access: ' + (t2 - t1));
})();
The difference is tiny, but it's there. When you have obj.prop, the interpreter first has to look up what obj refers to, and then it has to look up the prop property on obj to get to the value. So, it makes sense that it's a bit easier when the value you're looking for is already in a standalone variable - all that's necessary to get to it is for the interpreter to look up that variable.
But, for the example you mention, no matter what, you'll be doing one object lookup, and one plain value lookup:
foo(object); // 1 variable lookup
function foo(object) {
bar(object.item) // 1 object property lookup
}
// vs
foo(object.item); // 1 object property lookup
function foo(item) {
bar(item); // 1 variable lookup
}
It would be different if foo used the .item property more than once. For example, if foo had:
foo(object); // 1 variable lookup
function foo(object) {
bar(object.item) // 1 object property lookup
baz(object.item) // 1 object property lookup
}
that would require two object property lookups, which means it would be (very slightly) more efficient to pass the item alone.
All this said, the difference really is minuscule. As you can see with the snippet, it requires one billion iterations (at least on my machine) to reliably see a difference, and even then, the improvement is only ~5-10% or so, at least for me on Chrome. It's not something worth worrying about in 99% of situations. Code readability is more important.
I saw following code in a project. can anyone explain what is going on here? What will be value of Attributes? What is happening this[Attributes] = attrs line?
const Attributes = Symbol('User#attrs');
class User {
constructor (attrs) {
this[Attributes] = attrs;
}
}
Symbol creates an un-collidable key for any object:
const first = Symbol('debug-name');
const second = Symbol('debug-name');
first !== second // true;
const anObj = {};
anObj[first] = 123;
anObj[second] = 456;
console.log(anObj) // {Symbol('debug-name'): 123, Symbol('debug-name'): 456}
Note that even though the first and second variables have the same debugging string they create different keys in anObj. Anyone who has access to first can add that key to any object and it will not collide with any other key in that object.
This can be used instead of magic strings to manage protocols:
// ES5
someObject.MY_LIB_attributes = [1, 2, 3];
// Only safe if no other library uses the key
// "MY_LIB_attributes"
// ES2015+
export const Attributes = Symbol('myLib#attributes');
import { Attributes } from 'my-lib';
someObj[Attributes] = [1, 2, 3];
// Safe as long as no other library uses
// *this* Symbol instance for some other purpose.
Edit
Since you've now clarified the question to be only about the line of code this[Attributes] = attrs, see the second part of my answer for discussion of that.
Original Answer
This is a couple of the new ES6 Javascript features.
const Attributes = Symbol('User#attrs'); creates a new Symbol object. The Symbol function and object is described here. It creates a unique identifier object that can then be used for many other uses, one of which is as a property name. There are many other references on the new Symbol feature so I won't repeat all of that here.
The class definition is the ES6 method for declaring prototyped classes. Again, there are many other references on this new syntax so there is no point in repeating all that here. There's an example below of what the equivalent ES5 code is.
This line this[Attributes] = attrs; uses the Symbol generated above to set a property on the newly created object.
The class definition is equivalent to the regular constructor
declaration like this:
function User(attrs) {
this[Attributes] = attrs;
}
Discussion of this[Attributes] = attrs
Attributes is a symbol which can be used as a property name on an object. It's a way of generating a unique key that can be used as a property name. So, this[Attributes] = attrs is setting a property on the newly constructed object and it is using the Attributes symbol as the property name. This Attributes symbol is a unique value that will not match any known string (in fact it won't even match other Symbol objects) so it's a way of making a unique property name.
It is unclear why the code does this:
this[Attributes] = attrs;
instead of just something like this:
this.attrs = attrs;
We would have to see a bit more context for how that is being used and why a plain string property could not also be used in place of the Symbol as you haven't provided enough context for us to know.
One possible use is for privacy. If Attributes is not public, then this is a way of creating a property on the object that the outside world doesn't know how to access because you have to have the current value of Attributes in order to access that properly. As you've shown the code with User and Attributes in the same scope that does not seem like it is private, but perhaps only User is exported to a public scope.
Another possible use is for uniqueness. If the User object may have lots of other properties added to it by other code, then Attributes creates a unique property name that cannot collide with other property names. This seems less likely in this case, but it is one possible use of Symbols.
What is the difference between a JS:
Object, Property and Variable ?
Sorry I'm new to JavaScript but from the way I'm understanding it is a Variable is a container to store information/data types yes ?
An object is a variable but with several different properties (whereas with a variable you have one property)? name:value pairs
a property is the building blocks of objects? is that what makes an Object an Object? because it is a variable with several name:value pairs? ........
I'm supper confused!!! are all three the same are they like interchangeable?
the only example I can think of is
Human body:
Cells
Tissues
Organs
-organs are made up of tissues
-tissues are made up of cells
-cells are tissues, basically lots of cells make up tissues and lots of tissues make up organs.
So basically organs are also cells but they are made up of a lot of cells?
I'm a bit dumb and slow when it comes to learning can somebody please enlighten me?
Explain the differences between them in very simple basic language like your explaining it to a 10 year old or something please
answers much appreciated,
Thanks :)
ps There may be a part 2 to this question
the way I'm understanding it is a Variable is a container to store information/data types yes ?
Almost. A variable is a container that stores a value. Each value is of a specific data type. Common types are number, string and Boolean.
Example:
var userID = 42;
userID is a variable. It contains the value 42. 42 is a number value, i.e. it is of type number.
A JavaScript object is a value of type object. Objects are not just simple, scalar values, they are "container" values. They can themselves contain multiple different values.
Essentially objects are key-value stores, i.e. they contain one or more keys associated with a value. These key-value pairs are called properties.
Example:
var record = {
name: 'Paul',
age: 42
};
record is a variable. It contains an object as value. The object has two properties, name and age. name holds a string value, age a number value.
When one refers to 'variable' one typically imagine a container with some memory to hold a value.
Objects are variables too but dynamically transform to containers of primitives or more-complex values upon Assignment! Complex values can be objects that hold primitive data types or even other objects such in the example below :
var SNOCounter; //gives undefined ^
SNOCounter = 3;
AccObjVar = {firstName:"John", lastName:"Smith"}; //creates an JS "object" variable with two "properties" that hold 'string' type values
AccountWrapperObj = {SNO:SNOCounter,AccountName:AccObjVar};
The dynamism of object properties is such that although AccountWrapperObj which is a JS Object holds a primitive value and Object as its original value. Replacing the AccountName property with an integer can be done by just assigning it the integer value (the properties have dynamic data types just like variables in Javascript)
AccountWrapperObj.AccountName= 'Albert Einstein'; // changes the type of AccountName from AccObjVar object type to a String
----------Extra Info ---------------
^ I am not quite clear on the memory assignment part at this stage. Link says there needs to be a bare minimum memory here for referencing the variable and actually assigning it a value.
Does declaring a variable in JavaScript with var without assignment consume memory?
A variable is a binding to a value in memory and not an object.
The item in a box analogy isn’t quite right. I think that it’s more along the lines of two tin cans connected by a string, one can being the reference(variable) and the other being the value.
I'm also new to JS, so I'll tell what's helping me here
one thing that's helping me is to think about variables as 'labels', something temporary related to execution (a metaphor from Luciano Ramalho's Fluent Python book...), and not as 'boxes', a metaphor that I've seen in a lot of tutorials
so variables are temporary, and related to execution of some function, or of the whole script (depending of where they're declared... see the difference of var, let and const for more about this)
properties, on the other hand, are related to objects, attached to the obj while it or the property exists; so you cannot create a property that's not related to an obj
let myObj = {}; // 'myObj' is the 'label' of the obj we're creating
myObj.prop = true; // we create 'prop', a property of 'myObj', using the dot notation
almost everything in JS is an obj, and objs are custom types/structures for data; functions are also objects, but they're a 'special' kind of obj, we can create and return objects with them (we can execute functions to create/return objs); so
let foo; // declaring an empty variable; the word let is related to the scope of the variable, you can use var, let or const when declaring variables
foo = function(){ return {}; }; // foo returns an empty obj
myObj = foo(); // we execute foo() so that myObj is again an empty obj
the value of a property can also be an object, so we can also do
myObj.foo = function(...args){ // receives no or more arguments
const createProps = (el, i) => { // declares a variable and defines an arrow function
this[`prop${i+1}`] = el; // uses the index of the argument to create the name of the property, with the argument value
}
args.forEach(createProps); // for each arg, create a property
}
myObj.foo('some', 'new', 'properties'); // execute the function, creating new properties in 'myObj'
above, the function that creates properties for my myObj is part of myObj, as a property...
so objects and properties have to do with data structuring, how I relate the different kinds of data in my code; and functions and variables - these 'temporary labels' - have to do with execution, doin' stuff, creating objs, and so on... both 'portions' workin' together, of course
I receive a bunch of objects via JSON which ultimately need to have some instance member functions.
Is there a way to do this without copying the data?
For example:
var DataObject = function() {};
DataObject.prototype.add = function() { return this.a + this.b; };
var obj = JSON.parse('{"a":1, "b":2}');
// Do something to obj to make it inherit from DataObject
console.assert( obj.add() === 3 );
I've tried setting obj.prototype = DataObject.prototype but that doesn't seem to work. What am I missing?
Well, in ECMAScript6 (in IE11, and every other non ie browser today), that would be __proto__
obj.__proto__ = Object.create(DataObject.prototype);
[fiddle]
Generally, make sure you only do this at the object creation case, otherwise it can be very risky to do.
Also note, setting the protoype explicitly is not always faster than copying two properties, as you can see here so you have to be sure there is actual gain here.
I'm making a class that will be recreated many times, and in order to save memory I need to thoroughly delete it. Basically I need to access its containing variable if possible.
Here's the example:
function example(){
this.id=0;
this.action=function(){alert('tost');}
this.close=function(){ delete this;}
}
var foo=new example();
My question is:
How can I get access to the foo variable from within the example function so I can remove it?
window.foo will access that global variable.
this.close=function(){ delete window.foo; }
However, I remember there is something fishy with global variables, delete and window, so you might want to do otherwise, and simply use window.foo = null; for example.
If you want to access a variable defined in another function, you'll want to read the answers to this SO question.
Since what you want is to allow the garbage collector to release that object, you need to ensure that there are no references left to the object. This can be quite tricky (i.e. impossible) because the code manipulating the object can make multiple references to it, through global and local variables, and attributes.
You could prevent direct reference to the object by creating a proxy to access it, unfortunately javascript doesn't support dynamic getters and setters (also called catch-alls) very well (on some browseres you might achieve it though, see this SO question), so you can't easily redirect all field and method (which are just fields anyway) accesses to the underlying object, especially if the underlying object has many fields added to it and removed from it dynamically (i.e. this.anewfield = anewvalue).
Here is a smiple proxy (code on jsfiddle.net):
function heavyobject(destroyself, param1, param2) {
this.id=0;
this.action=function(){alert('tost ' + param1 + "," + param2);};
this.close=function(){ destroyself(); }
}
function proxy(param1, param2) {
object = null;
// overwrites object, the only reference to
// the heavyobject, with a null value.
destroyer = function() { object = null; };
object = new heavyobject(destroyer, param1, param2);
return function(fieldname, setvalue) {
if (object != null) {
if (arguments.length == 1)
return object[fieldname];
else
object[fieldname] = setvalue;
}
};
}
var foo = proxy('a', 'b');
alert(foo("action")); // get field action
foo("afield", "avalue"); // set field afield to value avalue.
foo("action")(); // call field action
foo("close")(); // call field close
alert(foo("action")); // get field action (should be 'undefined').
It works by returning a function that when called with a single argument, gets a field on the wrapped object, and when called with two arguments sets a field. It works by making sure that the only reference to the heavyobject is the object local variable in the proxy function.
The code in heavyobject must never leak this (never return it, never return a function holding a reference to var that = this, never store it into a field of another variable), otherwise some external references may be created that would point to the heavyobject, preventing its deletion.
If heavyobject's constructor calls destroyself() from within the constructor (or from a function called by the constructor), it won't have any effect.
Another simpler proxy, that will give you an empty object on which you can add fields, read fields, and call methods. I'm pretty sure that with this one, no external reference can escape.
Code (also on jsfiddle.net):
function uniquelyReferencedObject() {
object = {};
f = function(field, value) {
if (object != null) {
if (arguments.length == 0)
object = null;
else if (arguments.length == 1)
return object[field];
else
object[field] = value;
}
};
f.destroy = function() { f(); }
f.getField = function(field) { return f(field); }
f.setField = function(field, value) { f(field, value); }
return f;
}
// Using function calls
o = uniquelyReferencedObject();
o("afield", "avalue");
alert(o("afield")); // "avalue"
o(); // destroy
alert(o("afield")); // undefined
// Using destroy, getField, setField
other = uniquelyReferencedObject();
other.setField("afield", "avalue");
alert(other.getField("afield")); // "avalue"
other.destroy();
alert(other.getField("afield")); // undefined
The truth is that you can not delete objects in Javascript.
Then you use delete operator, it accepts the property of some object only.
So, when you use delete, in general you must pass to it something like obj.p. Then you pass just a variable name actually this means 'property of global object', and delete p is the same as delete window.p. Not sure what happens internally on delete this but as a result browser just skip it.
Now, what we actually deleting with delete? We deleting a reference to object. It means object itself is still somethere in memory. To eliminate it, you must delete all references to concrete object. Everythere - from other objects, from closures, from event handlers, linked data, all of them. But object itself doest have information about all this references to it, so there is no way to delete object from object itself.
Look at this code:
var obj = <our object>;
var someAnother = {
...
myObjRef: obj
...
}
var someAnotherAnother = {
...
secondRef : obj
...
}
To eliminate obj from memory you must delete someAnother.myObjRef and someAnoterAnother.secondRef. You can do it only from the part of programm which knows about all of them.
And how we delete something at all if we can have any number of references everythere? There are some ways to solve this problem:
Make only one point in program from there this object will be referenced. In fact - there will be only one reference in our program. and Then we delete it - object will be killed by garbage collector. This is the 'proxy' way described above. This has its disadvantages (no support from language itself yet, and necessarity to change cool and nice obj.x=1 to obj.val('x',1). Also, and this is less obvious, in fact you change all references to obj to references to proxy. And proxy will always remain in memory instead of object. Depending on object size, number of objects and implementation this can give you some profit or not. Or even make things worse. For example if size of your object is near size of proxy itself - you will get no worth.
add to every place there you use an object a code which will delete reference to this object. It is more clear and simple to use, because if you call a obj.close() at some place - you already knows everything what you need to delete it. Just instead of obj.close() kill the refernce to it. In general - change this reference to something another:
var x = new obj; //now our object is created and referenced
x = null;// now our object **obj** still im memory
//but doest have a references to it
//and after some milliseconds obj is killed by GC...
//also you can do delete for properties
delete x.y; //where x an object and x.y = obj
but with this approach you must remember that references can be in very hard to understand places. For example:
function func() {
var x= new obj;// our heavy object
...
return function result() {
...some cool stuff..
}
}
the reference is stored in closure for result function and obj will remain in memory while you have a reference to result somethere.
It hard to imagine object that is heavy itself, most realistic scenario - what you have some data inside it. In this case you can add a cleanup function to object which will cleans this data. Let say you have an gigant buffer (array of numbers for example) as a property of the object, and if you want to free memory - you can just clear this buffer still having object in memory as a couple dozens of bytes. And remember to put your functions to prototype to keep instances small.
Here is a link to some very detailed information on the JavaScript delete operator.
http://perfectionkills.com/understanding-delete/