Is there some kind of way of having some kind of "shared" variable? What I want to do is this:
var id = 5;
var player = new Player(id);
var array1[0] = player;
var array2[0] = player;
array1[0].id = 8
console.log(array1[0]); //8
console.log(array2[0]); //8
In JavaScript, you do not store an object directly in a variable, but rather a reference to the object.
That means, you can have two variables that point to the same object - you simply copy the reference:
var a = {test: "test"};
var b = a;
console.log(a === b) // true
In this case, if you mutate the object via a and later read it via b, you will see the changes.
With the right implementation of Player, you can make that work for you:
var Player = function(id) {
this.id = id;
}
Player.prototype.setId = function(id) {
this.id = id;
}
Player.prototype.getId = function() {
return this.id;
}
var player = new Player(5);
console.log(player.getId()); // 5
var arrA = [];
var arrB = [];
arrA.push(player);
arrB.push(player);
console.log(arrA[0].getId()); // 5
console.log(arrB[0].getId()); // 5
arrA[0].setId(10);
console.log(arrA[0].getId()); // 10
console.log(arrB[0].getId()); // 10
Check MDN for more info on working with objects.
I have this:
var a = {};
a[1] = 1;
a[4] = 4;
console.log(JSON.stringify(a));
then I get:
{"1":1,"4":4}
but I want to get:
{1:1,4:4}
how to reach this? In other words, I want to keys be real int.
When you call JSON.stringify() method it creates a valid JSON string.
One of the rules for valid JSON is that every property should be in "quotes".
So thats why it is impossible to get such result as you want using JSON.stringify.
If you want to just convert such object to array it is possible, for example usin such function.
function numerableObjectToArr(obj) {
var result = [];
var keys = Object.keys(obj);
keys.forEach(function(item){
result.push(obj[item]);
})
return result;
}
var a = {};
a[1] = 1;
a[4] = 4;
numerableObjectToArr(a); // returns [1, 4]
But in this way you will just receive Array with values of existing properties in the obj.
But if your prop name means the index in the array, and you are sure that there will be always number as a prop name - you can improve this function:
function numerableObjectToArr(obj) {
var result = [];
var keys = Object.keys(obj);
keys.forEach(function(item){
result[+item] = obj[item]; //we put index, then we put value to that place in array
})
return result;
}
var a = {};
a[1] = 1;
a[4] = 4;
numerableObjectToArr(a); // returns [undefined, 1, undefined, undefined, 4]
I'm not sure you can do what you're trying to do the as the keys have to be string values. I'd advise having string name for your keys (i.e 1 = One, 2 = Two, etc). You could then try this:
var a = {};
a.one = 1;
a.two = 2;
a.three = 3;
a.four = 4;
console.log(JSON.stringify(a));
I hope this helps.
var a = {};
a[1] = 1;
a[4] = 4;
alert(JSON.stringify(a).replace(/\"([0-9]+)\":/g, '$1:'));
But it is kludge. JSON - has a string keys.
There is something I can't find an answer or an explanation for. Let's take for example the following code:
function fn(x){
x = {value: 10};
}
var a;
fn(a);
alert(a.value); //a is undefined
Shouldn't a = {value: 10}; as we passed it through that function?
The x is locally scoped. You are passing only values and not references. So you might need to return and assign like this:
function fn(x){
x = {value: 10};
return x;
}
var a;
a = fn(a);
From an awesome article:
When passing in a primitive type variable like a string or a number, the value is passed in by value. This means that any changes to that variable while in the function are completely separate from anything that happens outside the function.
function myfunction(x)
{
// x is equal to 4
x = 5;
// x is now equal to 5
}
var x = 4;
alert(x); // x is equal to 4
myfunction(x);
alert(x); // x is still equal to 4
Passing in an object, however, passes it in by reference. In this case, any property of that object is accessible within the function.
function myobject()
{
this.value = 5;
}
var o = new myobject();
alert(o.value); // o.value = 5
function objectchanger(fnc)
{
fnc.value = 6;
}
objectchanger(o);
alert(o.value); // o.value is now equal to 6
I am trying to create a javascript object like
var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
But I am getting an error like allUserExpiry[aData.userId] undefined.
Is there a way, whereby I can set multi-level JS-Object keys? or is it important that I should go by doing allUserExpiry[aData.userId]={}, then allUserExpiry[aData.userId][aData.courseId]={} ?
Please let me know if there are any utility functions available for the same.
No, there is no way to set "multilevel keys". You need to initialize each object before trying to add properties to it.
var allUserExpiry = {};
allUserExpiry[aData.userId] = {}
allUserExpiry[aData.userId][aData.courseId] = {}
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;
Using Computed property names from ES6, it is possible to do:
var allUserExpiry = {
[aData.userId] = {
[aData.courseId]: {
[aData.uscId]: aData
}
}
};
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names
Simply use loadash,
let object = {};
let property = "a.b.c";
let value = 1;
_.set(object, property, value); // sets property based on path
let value = _.get(object, property, default); // gets property based on path
Or you can do it:
function setByPath(obj, path, value) {
var parts = path.split('.');
var o = obj;
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
if (!o[parts[i]])
o[parts[i]] = {};
o = o[parts[i]];
}
}
o[parts[parts.length - 1]] = value;
}
And use:
setByPath(obj, 'path.path2.path', someValue);
This approach has many weak places, but for fun... :)
Why not just do this?
var allUserExpiry={};
allUserExpiry[aData.userId] = {aData.courseId: {aData.uscId: aData}};
I have a pretty hacky but short way of doing it in IE9+ as well as real browsers.
Given var path = 'aaa.bbb.ccc.ddd.eee'; where path is what your intending to make into an object and var result = {}; will will create the object {aaa: {bbb: {ccc: {ddd: {eee: {}}}}}
result = {}
path.split('.').reduce(function(prev, e) {
var newObj = {};
prev[e] = newObj;
return newObj;
}, result);
will store the object in result.
How it works:
split('.') converts the input into ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
reduce(function (...) {...}, result) runs through the array created by split, and for each entry will pass along a returned value to the next one. In our case we pass the new object through after adding the new object to the old one. This creates a chain of objects. reduce returns the last object you return inside of it, so we have to defined result beforehand.
This relies on using references so it won't be immediately clear how it works if you're expecting your code to be maintained by anyone else and should probably be avoided to be honest, but it works at least.
You can also use the following to create the initial structure:
var x = function(obj, keys) {
if (!obj) return;
var i, t;
for (i = 0; i < keys.length; i++) {
if (!t) {
t = obj[keys[i]] = {};
} else {
t[keys[i]] = {};
t = t[keys[i]];
}
}
};
var a = {};
x(a, ['A', 'B', 'C', 'D', 'E', 'F']);
Another approach without strings or array as argument.
function fillObject() {
var o = arguments[0];
for(var i = 1; i < arguments.length-1; i++) {
if(!o.hasOwnProperty(arguments[i])) {
o[arguments[i]] = {};
}
if(i < arguments.length-2) {
o = o[arguments[i]];
}else {
o[arguments[i]] = arguments[i+1]
}
}
}
var myObj = {"foo":{}};
fillObject(myObj,"back","to","the","future",2);
console.log(JSON.stringify(myObj));
// {"foo":{},"back":{"to":{"the":{"future":2}}}}
But I wouldn't use it :-) It's just for fun.
Because I don't like too much intelligent algorithm. (If it was in this category)
Using lodash you can do this easily (node exists and empty check for that node)..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.
Another solution using reduce function (thanks Brian K).
Here we created a get/set to general proposes. The first function return the value in any level. The key is splited considering the separator. the function return the value refered from last index in the key's array
The second function will set the new value considering the last index of the splited key
the code:
function getObjectMultiLevelValue(_array,key,separator){
key = key.split(separator || '.');
var _value = JSON.parse(JSON.stringify(_array));
for(var ki in key){
_value = _value[key[ki]];
}
return _value;
}
function setObjectMultiLevelValue(_array,key,value,forcemode,separator){
key.split(separator || '.').reduce(function(prev, currKey, currIndex,keysArr) {
var newObj = {};
if(prev[currKey] && !forcemode){
newObj = prev[currKey];
}
if(keysArr[keysArr.length-1] == currKey){
newObj = value;
prev[currKey] = newObj;
}
prev[currKey] = newObj;
return newObj;
}, _array);
return _array;
}
//testing the function
//creating an array
var _someArray = {a:'a',b:'b',c:{c1:'c1',c2:{c21:'nothing here...'}}};
//a multilevel key to test
var _key = 'a,a1,a21';
//any value
var _value = 'new foo in a21 key forcing replace old path';
//here the new value will be inserted even if the path exists (forcemode=true). Using comma separator
setObjectMultiLevelValue(_someArray,_key,_value,true,',');
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//inserting another value in another key... using default separator
_key = 'c.c2.c21';
_value = 'new foo in c21 key';
setObjectMultiLevelValue(_someArray,_key,_value);
console.log('_someArray:');
console.log(JSON.stringify(_someArray));
//recovering the saved value with different separators
_key = 'a,a1,a21';
console.log(getObjectMultiLevelValue(_someArray,_key,','));
_key = 'c.c2.c21';
console.log(getObjectMultiLevelValue(_someArray,_key));
Let assume our object is
const data = {
//some other data
userInfo: {},
};
First, define a new property of that object
data.userInfo.vehicle = {};
then simply
data.userInfo.vehicle.vehicleType = state.userInfo.vehicleType;
In my program, I have declared an object myObject like this :
function myObject()
{
this.start=start;
function start(callbackFunction)
{
// Do something with callbackFunction
}
}
In my main() method, I create objects and I want to start nested callback like this :
var myObject1 = new myObject();
var myObject2 = new myObject();
var list = [];
list.push(myObject1);
list.push(myObject2);
var result = function() {};
var obj;
for (var i=list.length-1; i>=0; i--) {
obj = list[i];
result = function() { obj.start(result);}
}
result(); // I want to do myObject1.start(myObject2.start)); e.g. a nested callback
I don't understand why it doesn't work.
How can I correct my code ?
The result variable is redefined after each iteration.
Your need to set your function like so :
var myObject1 = new myObject();
var myObject2 = new myObject();
var list = [];
list.push(myObject1);
list.push(myObject2);
var result= function() {};
for (var i=list.length-1; i>=0; i--) {
var obj = list[i];
result = obj.start.bind(obj, result);
}
result();
Using the bind method will force the state of the variable to be saved at each iteration.
The problem is that you are not using closures properly.
In your for loop you declare a function that uses a variable from the outer scope (result). When the for loop ends, the result variable will contain the last function defined, instead of the one defined at step i, as you would expect.
One solution as you so very well hinted in a comment is recursivity:
function myObject(name)
{
this.name = name;
this.start= function(callbackFunction) {
console.log(this.name);
// Do something with callbackFunction
callbackFunction();
};
}
var myObject1 = new myObject(1);
var myObject2 = new myObject(2);
var list = [];
list.push(myObject1);
list.push(myObject2);
var runner = function(list, currentIndex) { // recursive function
if (currentIndex < 0) return function(){ console.log('INITIAL');};
return function(){
list[currentIndex].start(runner(list, currentIndex-1));
};
};
runner(list, list.length-1)();
DEMO: http://jsbin.com/ukeBUweG/2/edit
One last note, the solution above tries to stay true to your initial code. It is not
obj1.start(obj2.start(function(){}))
, but
function(){ obj1.start(function(){ obj2.start(function(){}) })}();