JavaScript undefined when using call() - javascript

obj = {}
obj.a = function(a) {
console.log(a); // returns undefined
//console.log('Obj.a')
}
obj.b = function(a) {
console.log(a); // returns undefined
//console.log('Obj.b')
}
var node = {
a: {
use:'a',
node:[
{
create:'item',
description:{name:'Samsung'},
}
]
},
b: {
use:'b',
node:[
{
create:'item',
description:{name:'Apple'},
}
]
}
}
for(name in node) {
if(node.hasOwnProperty(name)) {
a = node[name];
// console.log(name)
obj[name].call(a)
}
}
In the above code, why do I get undefined when calling functions obj.a and obj.b from the loop below, instead of the object that's being passed to it?

function.call. you should pass the object instance as first param
According to the MDN
Note: In certain cases, thisArg may not be the actual value seen by the method.
If the method is a function in non-strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.
obj = {}
obj.a = function(a) {
console.log(a); // returns undefined
//console.log('Obj.a')
}
obj.b = function(a) {
console.log(a); // returns undefined
//console.log('Obj.b')
}
var node = {
a: {
use: 'a',
node: [{
create: 'item',
description: {
name: 'Samsung'
},
}]
},
b: {
use: 'b',
node: [{
create: 'item',
description: {
name: 'Apple'
},
}]
}
}
for (name in node) {
if (node.hasOwnProperty(name)) {
a = node[name];
// console.log(name)
obj[name].call(obj,a)
}
}

Related

Why my 2 object deep comparison is failing?

I am trying to compare 2 objects using deep comparison and while comparison i want to ignore some properties.
My comparison is successful when I have those ignore properties on both the side of object.
But I am getting problem when I have 1 property missing in 2nd object which I want to ignore.
In my objA and objB, I want to ignore isParent and location property but as I don't have location property in objB, my object comparison is failing.
But I don't understand why I am getting false as I have specified location property to ignore.
var objA = {
isParent: true,
foo: {
location: "abc",
bar: "foobar"
}
};
var objB = {
isParent: false,
foo: {
bar: "foobar"
}
};
var comparator = function(left, right, key) {
if (key === 'isParent' || key === 'location') return true;//ignore isParent and location property while comparing 2 object
else return undefined;
}
var isEqual = _.isEqualWith(objA, objB, comparator);
console.log(isEqual); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Use the omit function to ignore unwanted properties then compare
var objA = {
isParent: true,
foo: {
location: "abc",
bar: "foobar"
}
};
var objB = {
isParent: false,
foo: {
bar: "foobar"
}
};
var isEqual = _.isEqual(
_.omit(objA, ['isParent', 'foo.location']),
_.omit(objB, ['isParent', 'foo.location'])
);
console.log(isEqual); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You can write your own compare function:
Logic:
Create a function that takes 2 objects that will be compared and an array(ignoreKeys) of keys that are to be ignored.
Get all keys from both object, merge them and then filter them into a new variable (say keys).
If the current key exists in keys, ignore it.
If the current key exists in ignoreKeys, ignore it
Else push it.
Now loop over these keys and check for comparison:
If current value is of type 'object', use recursion and start the process again.
Else, compare the values and return the comparison.
Since this has to be done for all the keys in keys, you can use Array.every.
Sample
function compareObject(obj1, obj2, ignoreProps){
var temp = Object.keys(obj1).concat(Object.keys(obj2)).sort();
var keys = temp.reduce(function(p,c) {
if(p.indexOf(c) < 0 && ignoreProps.indexOf(c) < 0) {
p.push(c);
}
return p;
}, []);
return keys.every(function(key){
var t1 = typeof(obj1[key])
var t2 = typeof(obj2[key])
if(t1 === t1) {
switch(t1) {
case 'object':
if(obj1[key] !== null && obj2[key] !== null)
return compareObject(obj1[key], obj2[key], ignoreProps);
else
return obj1[key] === obj2[key];
default: return obj1[key] === obj2[key];
}
}
})
}
var objA = {
isParent: true,
foo: {
location: "abc",
bar: "foobar",
test: {
location: 'bla',
test1: {
location: 'bla bla',
value: null
}
}
}
};
var objB = {
isParent: false,
foo: {
bar: "foobar",
test: {
location: 'new',
test1: {
location: 'new new',
value: null
}
}
}
};
var ignoreProperties = ['isParent', 'location'];
console.log(compareObject(objA, objB, ignoreProperties));
You could take all keys of the given objects and iterate and check if either
is a key of a no value check (ignore),
has same values or
both values are truthy and objects and the call of check returns a truthy value.
The keys of the properties to ignore are collected in an object.
function check(o, p) {
var keys = [...new Set(Object.keys(o).concat(Object.keys(p)))];
return keys.every(k => noValueCheck[k]
|| o[k] === p[k]
|| o[k] && p[k] && typeof o[k] === 'object' && typeof p[k] === 'object' && check(o[k], p[k])
);
}
var noValueCheck = { isParent: true, location: true },
objA = { isParent: true, foo: { location: "abc", bar: "foobar" } },
objB = { isParent: false, foo: { bar: "foobar" } };
console.log(check(objA, objB));

Javascript: object1 = object2 produce what exactly?

If I have 2 type of objects:
object1 : {
value : { foo1: {}, foo2: 5 }, state: true, etc = {}
}
And
object2 : {
value : { foo1: { value: 5}, foo2: 6 }, state: true, etc = {}
}
If I do object1=object2 what exactly happens with object1 on all levels please.
I'm going to simplify that a bit:
var a = { value: 1, aStuff: true };
var b = { value: 2, bStuff: true };
b = a;
console.log(b); // { value: 1, aStuff: true }
Now a and b reference the same object. Think of it like the same object is accessible by two names. Which means this happens when you change that object:
a.value = 5
console.log(a); // { value: 5, aStuff: true }
Two names, one object.
So what happened to what to the { value: 2, bStuff: true } object? Once you tell b to reference a different object then no existing variable has a reference to it, so eventually the garbage collector will find it and dispose of it.
What happens with inner objects? That is the question..
Nothing at all. The outer object still holds references the values it contains. All that's changed is that you have two variables pointing to that same outer object.
object1 is now a reference of object2, any change in object1, will change object2;
var object1 = { foo: 'bar' };
var object2 = {
value : { foo1: { value: 5}, foo2: 6 }
};
object1 = object2; // the { foo: 'bar' } is gone.
object1.foo2 = 7; //This changes object2.foo2 value
console.log(object2.foo2); //7

Filter array of objects

I get an array of objects from a MongoDB through API.
I then need to filter the result furthermore (client side).
I'll work with long lists (could be some thousand of results), each object has about 10 properties with some arrays in it.
Example of an object:
{
_id: xxxxxxx,
foo: [
{ a: "b", c: "d" },
{ a: "b", c: "d" }
],
data: {
a: "b",
c: "d"
}
}
I loop the array async to improve speed:
async.filter(documents, function(value) {
// Search inside the object to check if it contains the given "value"
}, function(results) {
// Will do something with the result array
});
How can I search inside the current object to check if it contains the given value without know in which property I'll find the value?
Though I've not included the async part but I believe overall searching approach could be like this:
// Input Array
var inpArr = [{
id: 1,
foo: [{
a: "dog",
b: "cat"
}]
}, {
id: 2,
foo: [{
a: "kutta",
b: "billi"
}]
}];
var myFilter = function(val, item, index, array) {
var searchResult = scanProperties(item, val);
return searchResult;
};
// Note: pass additional argument to default filter.
// using Function.Prototype.Bind
var filterResult = inpArr.filter(myFilter.bind(null, "dog"));
alert(filterResult);
console.log(filterResult);
// Recursively scan all properties
function scanProperties(obj, val) {
var result = false;
for (var property in obj) {
if (obj.hasOwnProperty(property) && obj[property] != null) {
if (obj[property].constructor == Object) {
result = result || scanProperties(obj[property], val);
} else if (obj[property].constructor == Array) {
for (var i = 0; i < obj[property].length; i++) {
result = result || scanProperties(obj[property][i], val);
}
} else {
result = result || (obj[property] == val);
}
}
}
return result;
};
JS Fiddle Searching an Array of Objects
You can simply iterate through each and every item recursively, like this
var data = {
_id: 1243,
foo: [{
a: "b",
c: "d"
}, {
a: "b",
c: "d"
}],
data: {
a: "b",
c: "d"
}
};
function findValue(value) {
function findItems(document) {
var type = Object.prototype.toString.call(document);
if (type.indexOf("Array") + 1) {
return document.some(findItems);
} else if (type.indexOf("Object") + 1) {
return Object.keys(document).some(function(key) {
return findItems(document[key]);
});
} else {
return document === value;
}
}
return findItems;
}
console.log(findValue('dd')(data));
# false
console.log(findValue('d')(data));
# true

Javascript Nested Literal to string

I am looking for a technique to run over a object of nested properties and wish to join the properties'.
This is the object I'd like to join:
var array = {
prop1: {
foo: function() {
// Your code here
}
},
prop2: {
bar1: 'some value',
bar2: 'some other value'
}
};
The result should look like this:
[
[ 'prop1', 'foo' ],
[ 'prop2', 'bar1' ],
[ 'prop2', 'bar2' ]
]
Then I'd like to join the array to strings formatted like this:
prop1.foo
prop2.bar1
prop2.bar2
Any tips?
EDIT: Forgot to say it should work for deeper arrays too.
Something along these lines? http://jsfiddle.net/X2X2b/
var array = {
prop1: {
foo: function() {
// Your code here
}
},
prop2: {
bar1: 'some value',
bar2: 'some other value'
}
};
var newA = [],
newB = [];
for ( var obj in array ) {
for (var inObj in array[obj]) {
newA.push([obj, inObj]);
newB.push(obj + '.' + inObj);
}
}
console.log(newA);
console.log(newB);
This is quite a different problem now that you have specified that it needs to support arbitrary depths. In order to solve it we need to use recursion and we need to use a second recursive parameter which keeps track of where we are in the nested hierarchy.
function objectPropertiesToArrays(obj, prepend) {
// result will store the final list of arrays
var result = [];
// test to see if this is a valid object (code defensively)
if(obj != null && obj.constructor === Object) {
for (var propertyName in obj) {
var property = obj[propertyName],
// clone prepend instantiate a new array
list = (prepend || []).slice(0);
// add the property name to the list
list.push(propertyName);
// if it isn't a nested object, we're done
if (property.constructor !== Object) {
result.push(list);
// if it is a nested object, recurse
} else {
// recurse and append the resulting arrays to our list
result = result.concat(objectPropertiesToArrays(property, list));
}
}
}
return result;
}
Example:
var obj = {
prop1: {
foo: function() { }
},
prop2: {
bar1: 'some value',
bar2: 'some other value'
},
prop3: {
x: {
y: [],
z: 'test'
},
erg: 'yar'
}
};
objectPropertiesToArrays(obj);
Returns
[
["prop1", "foo"],
["prop2", "bar1"],
["prop2", "bar2"],
["prop3", "x", "y"],
["prop3", "x", "z"],
["prop3", "erg"]
]

count 'last children' from any point in javascript object/array structure

I've got a data set simplified to the following
var data = {
foo: 'bar'
children: [
{
foo: 'bar'
children: [
{ foo: 'bar' }, // count
{ foo: 'bar' }, // count
{
foo: 'bar'
children: [
{ foo: 'bar' }, // count
{ foo: 'bar' }, // count
]
},
{ foo: 'bar' }, // count
]
},
{
// etc
}
]
}
There's a lot more of it than that. Any number of objects below nested.
{
foo: 'bar'
children: []
}
I want to be able to calculate the total 'last children' of any 'node' in the structure. So far I have written a quick script that will work it out from the top level using a counter variable scoped outside of the recursing function - but that stop it being re-usable.
var total = 0;
var countLastChildren = function(object) {
if(object.children) {
object.children.forEach(function(el){
countLastChildren(el);
});
} else {
total++;
}
}
countLastChildren(data);
console.log(total);
I can't quite get my head round how to scope the counter inside countLastChildren() to allow it to return a value and make it re-usable by passing in different objects or objects nested within my main structure.
Any ideas? Thanks
You can just have the function return the count:
var countLastChildren = function(object) {
if(object.children) {
var return_val = 0;
object.children.forEach(function(el){
return_val += countLastChildren(el);
});
return return_val;
} else {
return 1;
}
}
console.log(countLastChildren(data));
Some code golf:
function Total(obj) {
return obj.children
? obj.children.map(Total).reduce(function (prev, cur) { return prev + cur; })
: 1;
}

Categories

Resources