Dynamically assign value to undefined variable - javascript

I'm sure there is a simple way to do this, but am stumped for now.
I have many variables defined at the top of my script (here is an example of two):
var firstVar,secondVar;
Then I have an object which contains those variables:
var myObj = { a: {name:firstVar, number:1}, b: {name:secondVar, number:2}
I want to assign values to those variables:
keys = Object.keys(myObj);
function getAll(e){
var myArray = [];
for (var prop in myObj){
myArray.push(myObj.prop[e]);
}
return myArray;
}
The behaviour I want is:
var nameVars = getAll(name);
// [firstVar,secondVar]
But instead it returns:
// [undefined,undefined]
How else can I get the variables before defining them?

Then I have an object which contains those variables:
No, it doesn't. It contains a copy of the value those variables contained as of when you created the object (which is undefined, since you've never assigned a value to them). Once created, there is no ongoing link between the object property you've copied the value to and the variable.
Since the object has no enduring link to the variables, there's no way for getAll to return the information you've said you want.
You've said in a comment that you're building d3 graphs and have the same structure with some variables, and want to avoid repeating yourself. It sounds to me like you want a builder function:
function buildObject(firstVar, secondVar) {
return { a: {name:firstVar, number:1}, b: {name:secondVar, number:2} };
}
...which you would then use like this:
var obj1 = buildObject("value1", "value2");
// do a graph
var obj2 = buildObject("valueA", "valueB");
// do a graph
...or possibly even something that just takes the variables and produces the graph:
function makeGraph(firstVar, secondVar) {
buildTheGraph({ a: {name:firstVar, number:1}, b: {name:secondVar, number:2} });
}
I don't think it is, but if it's the names you want, just put them in quotes (and also myArray.push(myObj.prop[e]); should be myArray.push(myObj[prop][e]); and getAll(name) should be getAll("name")), but again there's no link to the variables at all:
// Since they're not used, we don't even need these: var firstVar, secondVar;
var myObj = { a: { name: "firstVar", number: 1 }, b: { name: "secondVar", number: 2 } };
function getAll(e) {
var myArray = [];
for (var prop in myObj) {
myArray.push(myObj[prop][e]);
}
return myArray;
}
var nameVars = getAll("name");
console.log(nameVars);
...but note that having the names doesn't help you get the variable values later (unless you use eval, which you should seek to avoid).

Related

Trying to pass a name of some existing variable in order to read it's value [duplicate]

I used C++ before and I realized that pointers were very helpful. Is there anything in javascript that acts like a pointer? Does javascript have pointers? I like to use pointers when I want to use something like:
var a = 1;
var b = "a";
document.getElementById(/* value pointed by b */).innerHTML="Pointers";
I know that this is an extremely simple example and I could just use a, but there are several more complex examples where I would find pointers very useful. Any ideas?
No, JS doesn't have pointers.
Objects are passed around by passing a copy of a reference. The programmer cannot access any C-like "value" representing the address of an object.
Within a function, one may change the contents of a passed object via that reference, but you cannot modify the reference that the caller had because your reference is only a copy:
var foo = {'bar': 1};
function tryToMungeReference(obj) {
obj = {'bar': 2}; // won't change caller's object
}
function mungeContents(obj) {
obj.bar = 2; // changes _contents_ of caller's object
}
tryToMungeReference(foo);
foo.bar === 1; // true - foo still references original object
mungeContents(foo);
foo.bar === 2; // true - object referenced by foo has been modified
You bet there are pointers in JavaScript; objects are pointers.
//this will make object1 point to the memory location that object2 is pointing at
object1 = object2;
//this will make object2 point to the memory location that object1 is pointing at
function myfunc(object2){}
myfunc(object1);
If a memory location is no longer pointed at, the data there will be lost.
Unlike in C, you can't see the actual address of the pointer nor the actual value of the pointer, you can only dereference it (get the value at the address it points to.)
I just did a bizarre thing that works out, too.
Instead of passing a pointer, pass a function that fills its argument into the target variable.
var myTarget;
class dial{
constructor(target){
this.target = target;
this.target(99);
}
}
var myDial = new dial((v)=>{myTarget = v;});
This may look a little wicked, but works just fine. In this example I created a generic dial, which can be assigned any target in form of this little function "(v)=>{target = v}". No idea how well it would do in terms of performance, but it acts beautifully.
due to the nature of JS that passes objects by value (if referenced object is changed completely) or by reference (if field of the referenced object is changed) it is not possible to completely replace a referenced object.
However, let's use what is available: replacing single fields of referenced objects. By doing that, the following function allows to achieve what you are asking for:
function replaceReferencedObj(refObj, newObj) {
let keysR = Object.keys(refObj);
let keysN = Object.keys(newObj);
for (let i = 0; i < keysR.length; i++) {
delete refObj[keysR[i]];
}
for (let i = 0; i < keysN.length; i++) {
refObj[keysN[i]] = newObj[keysN[i]];
}
}
For the example given by user3015682 you would use this function as following:
replaceReferencedObj(foo, {'bar': 2})
Assigning by reference and arrays.
let pizza = [4,4,4];
let kebab = pizza; // both variables are references to shared value
kebab.push(4);
console.log(kebab); //[4,4,4,4]
console.log(pizza); //[4,4,4,4]
Since original value isn't modified no new reference is created.
kebab = [6,6,6,6]; // value is reassigned
console.log(kebab); //[6,6,6,6]
console.log(pizza); //[4,4,4,4]
When the compound value in a variable is reassigned, a new reference is created.
Technically JS doesn't have pointers, but I discovered a way to imitate their behavior ;)
var car = {
make: 'Tesla',
nav: {
lat: undefined,
lng: undefined
}
};
var coords: {
center: {
get lat() { return car.nav.lat; }, // pointer LOL
get lng() { return car.nav.lng; } // pointer LOL
}
};
car.nav.lat = 555;
car.nav.lng = 777;
console.log('*** coords: ', coords.center.lat); // 555
console.log('*** coords: ', coords.center.lng); // 777

Object.freeze() vs const

Object.freeze() seems like a transitional convenience method to move towards using const in ES6.
Are there cases where both take their place in the code or is there a preferred way to work with immutable data?
Should I use Object.freeze() until the moment all browsers I work with support const then switch to using const instead?
const and Object.freeze are two completely different things.
const applies to bindings ("variables"). It creates an immutable binding, i.e. you cannot assign a new value to the binding.
Object.freeze works on values, and more specifically, object values. It makes an object immutable, i.e. you cannot change its properties.
In ES5 Object.freeze doesn't work on primitives, which would probably be more commonly declared using const than objects. You can freeze primitives in ES6, but then you also have support for const.
On the other hand const used to declare objects doesn't "freeze" them, you just can't redeclare the whole object, but you can modify its keys freely. On the other hand you can redeclare frozen objects.
Object.freeze is also shallow, so you'd need to recursively apply it on nested objects to protect them.
var ob1 = {
foo : 1,
bar : {
value : 2
}
};
Object.freeze( ob1 );
const ob2 = {
foo : 1,
bar : {
value : 2
}
}
ob1.foo = 4; // (frozen) ob1.foo not modified
ob2.foo = 4; // (const) ob2.foo modified
ob1.bar.value = 4; // (frozen) modified, because ob1.bar is nested
ob2.bar.value = 4; // (const) modified
ob1.bar = 4; // (frozen) not modified, bar is a key of obj1
ob2.bar = 4; // (const) modified
ob1 = {}; // (frozen) ob1 redeclared
ob2 = {}; // (const) ob2 not redeclared
Summary:
const and Object.freeze() serve totally different purposes.
const is there for declaring a variable which has to assinged right away and can't be reassigned. variables declared by const are block scoped and not function scoped like variables declared with var
Object.freeze() is a method which accepts an object and returns the same object. Now the object cannot have any of its properties removed or any new properties added.
Examples const:
Example 1: Can't reassign const
const foo = 5;
foo = 6;
The following code throws an error because we are trying to reassign the variable foo who was declared with the const keyword, we can't reassign it.
Example 2: Data structures which are assigned to const can be mutated
const object = {
prop1: 1,
prop2: 2
}
object.prop1 = 5; // object is still mutable!
object.prop3 = 3; // object is still mutable!
console.log(object); // object is mutated
In this example we declare a variable using the const keyword and assign an object to it. Although we can't reassign to this variable called object, we can mutate the object itself. If we change existing properties or add new properties this will this have effect. To disable any changes to the object we need Object.freeze().
Examples Object.freeze():
Example 1: Can't mutate a frozen object
object1 = {
prop1: 1,
prop2: 2
}
object2 = Object.freeze(object1);
console.log(object1 === object2); // both objects are refer to the same instance
object2.prop3 = 3; // no new property can be added, won't work
delete object2.prop1; // no property can be deleted, won't work
console.log(object2); // object unchanged
In this example when we call Object.freeze() and give object1 as an argument the function returns the object which is now 'frozen'. If we compare the reference of the new object to the old object using the === operator we can observe that they refer to the same object. Also when we try to add or remove any properties we can see that this does not have any effect (will throw error in strict mode).
Example 2: Objects with references aren't fully frozen
const object = {
prop1: 1,
nestedObj: {
nestedProp1: 1,
nestedProp2: 2,
}
}
const frozen = Object.freeze(object);
frozen.prop1 = 5; // won't have any effect
frozen.nestedObj.nestedProp1 = 5; //will update because the nestedObject isn't frozen
console.log(frozen);
This example shows that the properties of nested objects (and other by reference data structures) are still mutable. So Object.freeze() doesn't fully 'freeze' the object when it has properties which are references (to e.g. Arrays, Objects).
Let be simple.
They are different. Check the comments on the code, that will explain each case.
Const - It is block scope variable like let, which value can not reassignment, re-declared .
That means
{
const val = 10; // you can not access it outside this block, block scope variable
}
console.log(val); // undefined because it is block scope
const constvalue = 1;
constvalue = 2; // will give error as we are re-assigning the value;
const obj = { a:1 , b:2};
obj.a = 3;
obj.c = 4;
console.log(obj); // obj = {a:3,b:2,c:4} we are not assigning the value of identifier we can
// change the object properties, const applied only on value, not with properties
obj = {x:1}; // error you are re-assigning the value of constant obj
obj.a = 2 ; // you can add, delete element of object
The whole understanding is that const is block scope and its value is not re-assigned.
Object.freeze:
The object root properties are unchangeable, also we can not add and delete more properties but we can reassign the whole object again.
var x = Object.freeze({data:1,
name:{
firstname:"hero", lastname:"nolast"
}
});
x.data = 12; // the object properties can not be change but in const you can do
x.firstname ="adasd"; // you can not add new properties to object but in const you can do
x.name.firstname = "dashdjkha"; // The nested value are changeable
//The thing you can do in Object.freeze but not in const
x = { a: 1}; // you can reassign the object when it is Object.freeze but const its not allowed
// One thing that is similar in both is, nested object are changeable
const obj1 = {nested :{a:10}};
var obj2 = Object.freeze({nested :{a:10}});
obj1.nested.a = 20; // both statement works
obj2.nested.a = 20;
Thanks.
var obj = {
a: 1,
b: 2
};
Object.freeze(obj);
obj.newField = 3; // You can't assign new field , or change current fields
The above example it completely makes your object immutable.
Lets look following example.
const obj = {
a: 1,
b: 2
};
obj.a = 13; // You can change a field
obj.newField = 3; // You can assign new field.
It won't give any error.
But If you try like that
const obj = {
a: 1,
b: 2
};
obj = {
t:4
};
It will throw an error like that "obj is read-only".
Another use case
const obj = {a:1};
var obj = 3;
It will throw Duplicate declaration "obj"
Also according to mozilla docs const explanation
The const declaration creates a read-only reference to a value. It
does not mean the value it holds is immutable, solely that the
variable identifier can not be reassigned.
This examples created according to babeljs ES6 features.

How to make an object "live" in Javascript without tying it to the DOM

I asked in IRC chat yesterday whether it was possible to have an element update with any changes to an object it references, rather than just keep the value it was given upon being declared. For example
Arr1 = [1,2,3]
i1 = Arr1.length-1
last1 = Arr1[i1]
Arr1.push(4)
Checking last1 at the end of this (arbitrary) example shows it has not updated to reflect the newly added value of 4, so objects in JS aren't "live" by default.
I'm a beginner but I'd worked this out from practice already, but was told this was actually the case... I guess my question wasn't understood.
NodeList objects are "live" however, and I'm wondering if there are other types of object in JS that do so, as it would obviously save lines of code spent updating them.
One important distinction here is that i1 does not "reference" anything here. It is simply storing the numeric result of the expression Arr1.length-1 when that line executed. Likewise, last1 may or may not reference the value that was the third element of Arr1 when line 3 executed, but it maintains no reference to Arr1 itself or anything about it.
As in some other programming languages, variables that are assigned to objects are references, so you can do this:
var obj1 = { prop1: "hello", prop2: "goodbye" };
var obj2 = obj1;
obj2.prop1 = "buongiorno";
console.log(obj1.prop1); // result is "buongiorno"
But this doesn't seem to be quite what you're describing.
It sounds like what you're describing is some sort of reactive programming. JavaScript doesn't really work the way you're imagining, but you could accomplish this using closures:
var Arr1 = [1,2,3];
var i1 = function() { return Arr1.length - 1; };
var last1 = function() { return Arr1[i1()]; };
console.log(i1()); // result is 2
console.log(last1()); // result is 3
Arr1.push(4);
console.log(i1()); // result is 3
console.log(last1()); // result is 4
Note that here, the () parentheses at the end are required to call these functions and get their current value.
One even trickier thing you could do is the following:
function capture(fcn) {
return { valueOf: fcn, toString: function() { return fcn().toString(); } };
}
var Arr1 = [1,2,3]
var i1 = capture(function() { return Arr1.length - 1; });
var last1 = capture(function() { return Arr1[i1]; });
console.log(last1 * 5); // result is 15
Arr1.push(4);
console.log(last1 * 5); // result is 20
Note however that this second technique has its limitations. You have to coerce the values into the type that you would expect or call their .valueOf() method in order for them to produce an actual value. If you just used:
console.log(last1);
You would not get any sort of friendly result.
I interpret your question as why are some variables which are copies are updated when you change the original value and others are not.
This is because some types of variables are Reference Types and others are Value Types. Numbers, dates and strings are value types and are copied whenever you assign them to a variable. Objects, Arrays (which are also an Object) are reference types and are not copied, just referenced.
This example is using value types and any change to the first variable will not be copied:
var foo = 1;
var bar = foo; // this is copying the value from the foo variable to bar
foo = 2;
console.log(bar); // 1
compared to the same thing but with a reference to an object:
var foo = {prop:1};
var bar = foo; // this is creating a reference to the foo object
foo.prop = 2;
console.log(bar.prop); // 2

How can I use a object reference stored in a variable as a string?

If I have a variable foo that hold a reference to an object:
var foo = someObj;
How can I then use the name of the object as a string?
I tried:
var bar = foo.valueOf()
But that just returned another reference to the object.
What I have is an algorithm that selects from a large number of objects. I then want to use the name of that object to select from amongst a group of HTML elements. Using the following does not work either (returns null):
document.getElementById(foo)
Thank you.
There is no reliable way to get the name of the object.
Example:
var obj = {};
var obj1 = obj;
var obj2 = obj;
magically_get_and_print_name(obj); // What to print? "obj"? "obj1"? "obj2"?
Methods to get the name in some cases:
Function declarations - funcreference.name (non-standard, though well-supported)
Constructor instances - instance.constructor.name
Let's say you have:
var someObj = {
a: 15,
b: 36
};
And then you did:
var foo = someObj;
There's no way to get the string "someObj" (or "foo") from foo.
What you could do, is add the name to the object when creating it. Something like this:
var someObj = {
a: 15,
b: 36,
objName: 'someObj'
};
var foo = someObj;
console.log(foo.objName); // "someObj"

Proper way to create object

What's the proper way to create an object (with its "namespaces" and such)?
1
//Company object
var Microsoft = {};
//Create an employee
Microsoft.employee = function(name) {
this.name = name;
}
or
2
//Company object
Apple = {
employee: function(name) {
this.name = name;
}
}
OR another way? Shoot.
Read something about prototypes and such. What's the proper way to do it; benefits and downsides?
First off, you forgot the var for Apple. But otherwise these are basically the same thing.
Secondly, in my examples I'm not going to use the attribute name since, when dealing with functions, the name is an empty string by default. At least in Node.js and Chrome. So I'll use empName instead.
In the Microsoft example you are making an empty object and then adding an attribute to it after the fact.
In the Apple example you are making an object with the attribute right away.
It's really just what makes the most sense to you, and which you prefer. Since they are, more or less, equivalent.
Now, this has nothing to do with prototypes. Here's an example of what you did:
var Apple = {
employee: function(empName) {
this.empName = empName;
}
};
Apple.employee('Hank');
Apple.empName; // 'Hank'
And here's how you would do this with an instance (using the new operator, and the prototype)
var Apple = function() {}; // base 'parent'
Apple.prototype.employee = function(empName) {
this.empName = empName
};
var a = new Apple();
a.employee('Hank');
a.empName; // 'Hank'
Apple.empName; // undefined
So prototype is used to add attributes to new instances of an object (using 'object' loosely). Note that to access employee in Apple, on this second example, you would have to do something like
Apple.prototype.employee('Hank'); // doesn't really do much
Apple.empName; // undefined
// but you can call the employee prototype with a bound variable
// you'd do this if you don't want to make an instance of Apple
// but still want to use one of it's prototypes
var obj = {};
Apple.prototype.employee.call(obj, 'Hank');
obj.empName; // 'Hank'
// a practical use of accessing a prototype method is
// when wanting to convert a function's arguments
// to an array. function arguments are like an array,
// but until turned into one they are not completely the same
var func = function() {
var args = Array.prototype.slice.call(arguments);
var sum = 0;
for(var i = 0, l = args.length; i < l; i++) {
sum += args[i];
}
return sum;
};
func(1); // 1
func(1, 2, 3, 4, 5); // 15
Hope that helps.
EDIT: Also, don't prototype objects (e.g. {} or Object). It's not safe to do this. Since, essentially, every variable in JavaScript is an object, then any prototypes you add to them will be available on all variables. So if you did Object.prototype.xyz = 12 then had var obj = { a: 1, b: 2, c: 3} and then tried for(var key in obj) { console.log(key); } you would result in the following logs: a, b, c and xyz ... which you wouldn't want.

Categories