Object.create() not fully creating; - javascript

Here is the code:
//Note: x actually isn't defined, I'm pulling it from an external source
var x = [{ name: 'Michael Lovesllamas Lankford',
created: 1338420951.11,
laptop: 'pc',
laptop_version: null,
userid: '4fc6aed7eb35c14ad6000057',
acl: 0,
fans: 1,
points: 5,
avatarid: 34 }]
global.UserBase = {
userid: -1,
name: "noidea",
isSuperUser: false,
isDJ: false,
laptop: "pc",
afkWarned: false,
afkTime: Date.now(),
droppedTime: null,
droppedRoom: null,
songCount: 0,
mWaitingSongLimit: 0,
totalSongCount: 0,
totalHeartCount: 0,
totalHeartsGiven: 0,
customGreeting: null,
bootAfterSong: false,
joinedTime: Date.now(),
whiteList: false,
allowedToReserveSpot: true
};
global.mUsers = {length:0};
global.Register = function(a) {
for(var i = 0; i < a.length; i++) {
var sUser = a[i];
mUsers[sUser.userid] = CreateUser(sUser);
mUsers.length++;
}
};
global.CreateUser = function(a) {
var b = Object.create(UserBase);
b.userid = a.userid;
b.name = a.name;
b.laptop = a.laptop;
if (a.acl > 0) b.isSuperUser = true;
return b;
};
Register(x);
Now, to the problem. Instead of mUsers[sUser.userid] becoming this:
'4fc6aed7eb35c14ad6000057': {
userid: "4fc6aed7eb35c14ad6000057",
name: "noidea",
isSuperUser: false,
isDJ: false,
laptop: "pc",
afkWarned: false,
afkTime: Date.now(),
droppedTime: null,
droppedRoom: null,
songCount: 0,
mWaitingSongLimit: 0,
totalSongCount: 0,
totalHeartCount: 0,
totalHeartsGiven: 0,
customGreeting: null,
bootAfterSong: false,
joinedTime: Date.now(),
whiteList: false,
allowedToReserveSpot: true
}
it becomes this:
'4fc6aed7eb35c14ad6000057': {
userid: '4fc6aed7eb35c14ad6000057',
name: 'Michael Lovesllamas Lankford',
laptop: 'pc'
}
Any ideas why the rest of the values in UserBase aren't being added to the object?

Object.create creates a new object and sets its prototype to the object you pass in.
Your object is getting initialized, but you're only explicitly setting a few properties on the new object instance. The properties from the prototype object (UserBase) are all accessible, but a direct console.log of the object won't print them.
E.g. after running your code, doing:
for(var p in mUsers['4fc6aed7eb35c14ad6000057']) {
console.log(p, mUsers['4fc6aed7eb35c14ad6000057'][p]);
}
prints out:
userid 4fc6aed7eb35c14ad6000057
name Michael Lovesllamas Lankford
laptop pc
isSuperUser false
isDJ false
afkWarned false
afkTime 1340089066700
droppedTime null
droppedRoom null
songCount 0
mWaitingSongLimit 0
totalSongCount 0
totalHeartCount 0
totalHeartsGiven 0
customGreeting null
bootAfterSong false
joinedTime 1340089066700
whiteList false
allowedToReserveSpot true

UserBase is on global object, and you need to call Register on global object.
global.CreateUser = function(a) {
var b = Object.create(this.UserBase);
b.userid = a.userid;
b.name = a.name;
b.laptop = a.laptop;
if (a.acl > 0) b.isSuperUser = true;
return b;
};
global.Register(x);

this is happening beacause you are only initializing the values for
userid,
name and laptop.
see your code:
b.userid = a.userid;
b.name = a.name;
b.laptop = a.laptop;
to get the desired result, you need to call Global.Register(x) instead of Register(x)

Related

How to sort array of objects with boolean values: true, false and null

Hi i have an array of objects that i want to sort based on a boolean that one of the objects has. However normally there would be either true or false but in this case we also check on null values because sometimes the data has not been set and in that case we wanna show that it has yet to be set with an icon.
Here's an example of the array:
const arrayOfObjects = [
{
id: 69,
boolean: true,
name: 'foo',
},
{
id: 42,
boolean: false,
name: 'bar',
},
{
id: 666,
boolean: null,
name: 'foo',
},
{
id: 420,
boolean: false,
name: 'bar',
},
{
id: 2,
boolean: null,
name: 'foo',
},
{
id: 123,
boolean: true,
name: 'foo',
},
]
So what i tried first was:
arrayOfObjects.sort((a, b) => b.boolean - a.boolean);
This sets the objects that are true at the front but the objects with false or null are scattered.
Then i tried:
arrayOfObjects.sort((a, b, c) => (c.boolean - b.boolean) - a.boolean);
This just didn't work at all.
I couldn't really find a case that was similar enough to base a solution off of it so hopefully i can find it here.
If you like to use a custom sorting, you could take an object with the wanted sorting, like
const
order = { true: 1, null: 2, false: 3 };
data = [{ id: 69, boolean: true, name: 'foo' }, { id: 42, boolean: false, name: 'bar' }, { id: 666, boolean: null, name: 'foo' }, { id: 420, boolean: false, name: 'bar' }, { id: 2, boolean: null, name: 'foo' }, { id: 123, boolean: true, name: 'foo' }];
data.sort((a, b) => order[a.boolean] - order[b.boolean]);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you have unknown values and want to move them to bottom, you could add another key with a large value, like
order = { true: 1, null: 2, false: 3, bottom: Number.MAX_VALUE };
Usage:
data.sort((a, b) =>
(order[a.boolean] || order.bottom) - (order[b.boolean] || order.bottom)
);
You can check for the null explicitly ...
let list = [{i: 0, boolean: true}, { i: 1, boolean: null}, { i:2, boolean: false}, { i: 4, boolean: true}]
function cpBoolWithNull(a,b) {
//if both are null return 0 to maintain a stable sort
//if only one is null return 0 or 1 depending on the value of the other
if (a.boolean === null) return b.boolean === null ? 0 : b.boolean ? 1 : -1;
if (b.boolean === null) return a.boolean ? -1 : 1;
//if both are different from null, sort true before false
return b.boolean - a.boolean
}
console.log(list.sort(cpBoolWithNull));
This will sort true ... null ... false If you need a differnt order, adjust the return values.
I think that you can have a type checker with JS with this simple script.
let array =[true, false, null];
function check(i){
if (array[i] != null||array[i]!=false){
if (array[i]!=null || array[i]!=true)document.write(" Array item"+" "+i+" "+"has the value of boolean false. ");
if (array[i]!=true||array[i]!=false)document.write(" Array item"+" "+i+" "+"has the value of boolean true. ");
if (array[i] != true || array[i] != false )document.write(" Array item"+" "+i+" "+"has the value of object null. ");
document.write("<br>")
}
}
check(0);
You can comment out the other text when it is not needed.

Compare Nested Objects and save difference in new object using Javascript

I have two Javascript objects
var order1 = {
sandwich: 'tuna',
chips: true,
drink: 'soda',
order: 1,
toppings: [{VendorNumber: 18, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 19, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 20, PreferredFlag: false, SupportedFlag: true}],
details: {
name: 'Chris',
phone: '555-555-5555',
email: 'no#thankyou.com'
},
otherVal1: '1'
};
var order2 = {
sandwich: 'turkey',
chips: true,
drink: 'soda',
order: 2,
toppings: [{VendorNumber: 18, PreferredFlag: false, SupportedFlag: true}, {VendorNumber: 19, PreferredFlag: false, SupportedFlag: false}, {VendorNumber: 20, PreferredFlag: true, SupportedFlag: true}],
details: {
name: 'Jon',
phone: '(555) 555-5555',
email: 'yes#please.com'
},
otherVal1: '2'
};
What I need is to compare these two objects (order1 is existing and order2 is the edited data) and store the difference in a new variable named var order3. However if there is an array inside an object like the toppings array to be copied as whole with the changes.
In short the result should be
{
details: {
email: "yes#please.com",
name: "Jon",
phone: "(555) 555-5555"
},
order: 2,
otherVal1: "2",
sandwich: "turkey",
toppings: [{
PreferredFlag: false,
SupportedFlag: true,
VendorNumber: 18
}, {
PreferredFlag: false,
SupportedFlag: false,
VendorNumber: 19
}, {
PreferredFlag: true,
SupportedFlag: true,
VendorNumber: 20
}]
}
How can i achieve this ?
This gives you exactly what you wanted:
function diff(tgt, src) {
if (Array.isArray(tgt)) { // if you got array
return tgt; // just copy it
}
// if you got object
var rst = {};
for (var k in tgt) { // visit all fields
if (typeof src[k] === "object") { // if field contains object (or array because arrays are objects too)
rst[k] = diff(tgt[k], src[k]); // diff the contents
} else if (src[k] !== tgt[k]) { // if field is not an object and has changed
rst[k] = tgt[k]; // use new value
}
// otherwise just skip it
}
return rst;
}
console.log(diff(order2, order1));
I think you are looking for a diff'ing algorithm. Wrote this quick recursive function that iterates over each enumerable property of your JavaScript object (not json object) testing equality. Note that the position of arguments does affect the output
function diff(obj1, obj2) {
if (typeof obj1 === "object") {
const obj = {};
for (const prop in obj1) {
if (diff(obj1[prop], obj2[prop])) {
obj[prop] = obj1[prop]
}
}
return obj
} else {
return obj1 !== obj2;
}
}
console.log(diff(order2, order1))

Comparing a object with a test object

How can I compare the object with the test object in Javascript. And if the Testobject sets the same value to true output this Object Item into a new Object.
Obj1 = [{
name: Hugo,
itsTrustee: false,
itsSchollar: true,
},
{
name:Bugo,
itsTrustee: true,
itsSchollar: false,
}];
testObj = {
itsTrustee: true,
itsSchollar: false,
}
I tried Reduce and map. But I can't get the right value
Like that:
this.obj1.map((item) => {
let newObj = Object.keys(item).reduce((acc, x) => {
});
});
But since nothing works correctly, I cannot show an example function here
first you can restructure a little like this
Obj1 = [{
name: "Hugo",
something: {
itsTrustee: false,
itsSchollar: true
}
},
{
name: "Hugo",
something: {
itsTrustee: false,
itsSchollar: true
}
}
];
then you can try using find function here is an example
const data = [20, 18, 15, 10, 9];
let found = data.find(element => element < 12);
console.log(found);
for you it's going to be something like
let found = data.find(element => JSON.stringify(element.something) == JSON.stringify(testObj));
if found is null that's mean there's no object with your
wish it helped you

Using Underscore.js To Merge/Combine and Sum Array Entries

I have 2 arrays of JSON objects which I'm looking to merge/combine together and then sum up the quantities of any matching entries.
Both of the arrays contain the same structure, one represents a list of equipment that is required to be used...
var required = [
{ SerialisedEquipment: { SerialNo: "ser855212" }, Type: undefined, Serialised: true, Quantity: 1 },
{ SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Serialised: true, Quantity: 1 },
{ SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Serialised: false, Quantity: 5 },
{ SerialisedEquipment: undefined, Type: { ItemId: "itm11025" }, Serialised: false, Quantity: 2 }];
...and the other represents a list of equipment that actually has been used.
var used = [
{ SerialisedEquipment: { SerialNo: "ser663033" }, Type: undefined, Serialised: true, Quantity: 1 },
{ SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Serialised: true, Quantity: 1 },
{ SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Serialised: false, Quantity: 2 }];
I have access to underscore.js and have been trying to use the _.groupBy and _.reduce methods to try and get the result I'm after but with no success. The result I'm looking to achieve is:
var result = [
{ SerialisedEquipment: { SerialNo: "ser663033" }, Type: undefined, Used: 1, Expected: 0, Remaining: 0 },
{ SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Used: 1, Expected: 1, Remaining: 0 },
{ SerialisedEquipment: { SerialNo: "ser855212" }, Type: undefined, Used: 0, Expected: 1, Remaining: 1 },
{ SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Used: 2, Expected: 5, Remaining: 3 },
{ SerialisedEquipment: undefined, Type: { ItemId: "itm11025" }, Used: 0, Expected: 2, Remaining: 2 }];
I've also been looking at some of the Array methods that underscore provides but I'm not sure how I would use these to specify the criteria to merge by. Would anyone have any suggestions on the best way to achieve this?
UPDATE
I've managed to get the merged list of both of the arrays, removing duplicates...
// Split based on the serialised flag - so I know to look at either the serialNo or Type property
var isSerialised = _.groupBy(required, function (equip) {
return equip.Serialised;
});
// Get all the required serialised equipment that is not already in the used list
var serialised = _.filter(isSerialised[true], function (value) {
return (!_.some(used, function (equip) {
return equip.SerialisedEquipment && equip.SerialisedEquipment.SerialNo == value.SerialisedEquipment.SerialNo;
}));
});
// Get all the required types that are not already in the used list
var types = _.filter(isSerialised[false], function (value) {
return (!_.some(used, function (equip) {
return equip.Type && equip.Type.ItemId == value.Type.ItemId;
}));
});
// Combine the equipment that is not in the list with the equipment that is in the list
var result = _.union(used, serialised, types);
I think it's now just a case now of looping through this results list with the required equipment list and summing up equipment that match based on serial number or type.
Sometime wanting to use a library to much makes you miss simpler algorithms:
var resultsById = {};
function getTemporaryId(value) {
return value.SerialisedEquipment ? value.SerialisedEquipment.SerialNo : value.Type.ItemId;
}
function getResultForValue(value) {
var id = getTemporaryId(value);
if(!resultsById[id]) {
resultsById[id] = {
SerialisedEquipment: value.SerialisedEquipment,
Type: value.Type,
Used: 0,
Expected: 0,
Remaining: 0
};
}
return resultsById[id];
}
_.each(required, function(value) {
var result = getResultForValue(value);
result.Expected += value.Quantity;
result.Remaining += value.Quantity;
});
_.each(used, function(value) {
var result = getResultForValue(value);
result.Used += value.Quantity;
result.Remaining = Math.max(result.Remaining - value.Quantity, 0);
});
var merged = _.values(resultsById);
If you really want to use lots of underscore, you can play with this solution:
var requiredValues = _.map(required, (function(value){
//maybe want to clone value? value = _.clone(value);
value.Used = 0;
value.Expected = value.Quantity;
return value;
}));
var usedValues = _.map(used, (function(value){
//maybe want to clone value? value = _.clone(value);
value.Used = value.Quantity;
value.Expected = 0;
return value;
}));
var mergedValues = _.chain(requiredValues.concat(usedValues))
.groupBy(function(value){
return value.SerialisedEquipment ? value.SerialisedEquipment.SerialNo : value.Type.ItemId;
})
.map(function(values) {
var memo = {
SerialisedEquipment: values[0].SerialisedEquipment,
Type: values[0].Type,
Used: 0,
Expected: 0,
Remaining: 0
};
return _.reduce(values, function(memo, value) {
memo.Used += value.Used;
memo.Expected += value.Expected;
memo.Remaining = Math.max(memo.Expected - memo.Used, 0);
return memo;
}, memo)
})
.values()
.value();
You can just use Array.concat() method:
var result = required.concat(used);
and it will make merge for you.
EDIT
Though if you want to use undescore method _.union(arr1,arr2) is for you!

How can I use the binary system (1, 2, 4) as an algorithm?

Similar to chmod, I would like to use 1, 2, 4 as a way of notifications.
1 = Email
2 = SMS
4 = Push notifications
Is there function (preferably in javascript) that can input a number (above) and can return an object with:
{
email: true,
sms: true,
push: false
}
I want the function to not be hard coded. I don't want a bunch of if statements that check for every combination there is. I want a "smart" way to do it.
How about something like this:
var commsMode = {
email: 1,
sms: 2,
push: 4,
toObject: function(val){
var rt = {};
for (e in commsMode) {
rt[e] = (val & commsMode[e]) > 0;
}
return rt;
}
};
var obj = commsMode.toObject(3);
Working example here.
Extended example:
var commsMode = {
email: 1,
sms: 2,
push: 4,
mode4: 8,
mode5: 16,
mode6: 32,
mode7: 64,
mode8: 128,
toObject: function(val){
var rt = {};
for (e in commsMode) {
rt[e] = (val & commsMode[e]) > 0;
}
return rt;
}
};
var obj = commsMode.toObject(233);
for (p in obj) {
alert(p + ': ' + obj[p])
}
Working example here
Try something like this - sorry, this is Python, but the JavaScript translation should be very similar:
def notifications(mask):
return {
'email' : mask & 4 != 0,
'sms' : mask & 2 != 0,
'push' : mask & 1 != 0
}
notifications(0b111) # same as notifications(7), or notifications(email+sms+push)
=> {'push': True, 'sms': True, 'email': True}
In the above, we're saying that the notifications binary bit mask is 0b111 (or 7, if you prefer to use base-10), meaning that all three notifications are enabled. Similarly, if we had passed as bit mask 0b010 (or 2 in base-10), then the answer would have been:
notifications(0b010) # same as notifications(2), or notifications(sms)
=> {'push': False, 'sms': True, 'email': False}
Solution with multiple parameters to send to function:
var states = {
'1': 'email',
'2': 'sms',
'4': 'push'
};
function getStates(){
var o = {};
for(var val in states){
o[states[val]] = false;
}
for(var i=0;i<arguments.length;i++){
var arg = arguments[i];
var state = states[arg];
if(state){
o[state] = true;
}
}
return o;
}
console.log(getStates()); // return {email: false, sms: false, push: false}
console.log(getStates(1,2)); // return {email: true, sms: true, push: false}
http://jsfiddle.net/ZTA6E/

Categories

Resources