I need to loop through an objects keys and if the property is false then delete the keys property. This is what I have so far but I can't figure out what I am doing wrong.
function onlyTheTruthy() {
onlyTheTruthy.key;
var prop;
for (key in onlyTheTruthy){
if (key != true) {
delete onlyTheTruthy.key.prop
}
else {
}
}
return onlyTheTruthy;
};
In a for...in loop, use the key to access the value on the object. This is done with brackets like obj[key].
function onlyTheTruthy(obj) {
for (var key in obj) {
if (!obj[key]) {
delete obj[key];
}
}
return obj;
}
function onlyTheTruthy() {
onlyTheTruthy.key;
var prop;
for (key in onlyTheTruthy) {
if (key != true) {
delete onlyTheTruthy.key.prop
} else {}
}
return onlyTheTruthy;
};
This is your code.
Line:
You declare a function named onlyTheTruthy, taking no arguments. However, I think it ought to take one: o.
This line does nothing. It should be removed.
You set the scope of the variable prop, but give it no value. Fine.
A for...in loop. You may want to research exactly what that does. The key variable hasn't been seen before, other than on line 2, but that is a different variable: a property of onlyTheTruthy. Also, you're looping through the keys of the function you're inside of: onlyTheTruthy. I'm confident this isn't what you want. Try:
for (prop in o) {
Checking if key is not equal to true. Not too often are boolean values used as object keys. Maybe:
if (!o[prop]) { // Or, more verbosely:
if (o[prop] === false) {
Look up square brackets ([]).
Empty else. How about no else? It's not required, you know.
} Closing the for...in loop.
Returning the function itself. Nope. How about o? Or, if you end up modifying the object itself, there's no need for a return at all.
No semicolon necessary at the end of a function declaration.
Happy Coding!
Fixed version:
function onlyTheTruthy (o) {
for (var prop in o) {
if (!o[prop])
delete o[prop];
}
}
Related
I've got a problem with a CodeCademy task. I am to re-create the findKey lodash library method. Here there are the steps of how to do it, but I got stuck, especially at point 5.
Add a method to our _ object called findKey.
Add two parameters to this method: object and predicate. We will
name our predicate function parameter predicate since this is the
name used in the Lodash documentation.
Within the method, use a for ... in loop to iterate through each key
in object.
Within the loop, create a variable called value and set it equal to
the value at the current key in object.
Still within the loop, create another variable called
predicateReturnValue and set it equal to the result of calling
predicate with value.
Finally, still within the loop, use an if statement to check
if predicateReturnValue is truthy. If it is, return the current key
from the method.
Outside of the loop, return undefined to address all cases where no
truthy values were returned from predicate.
This is my code that doesn't work:
findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue === 'true') {
return value;
};
};
return undefined;
}
I appreciate your help!
You need to return the key after the truty check of the call of predicate.
function findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) { // just take the value
return key; // return key
}
}
}
const
isStrictEqual = a => b => a === b,
object = { a: 'foo', b: 'bar', c: 'baz' }
console.log(findKey(object, isStrictEqual('bar')));
console.log(findKey(object, isStrictEqual('cat')));
I have a for/in loop that I would like to know if I'm at the end of. I'm not entirely sure how this would work?
My code is:
for (const key in posts.val()) {
if(posts.val()[key][postId] != undefined) {
found = true;
//do something
} else {
// if at end && found !== true
}
}
Any idea how I would know if I'm at the end of the for/in loop?
Thank you!
There's no built-in functionality for something like that. Assuming the properties don't get mutated when .val() is called, you could call .val() initially to get the object, count up the number of keys (including inherited keys) with for..in, and then use for..in again to iterate and be able to test how close you are to the end of the loop:
const val = posts.val();
let totalKeyCount = 0;
for (const _ in posts.val()) {
totalKeyCount++;
}
let keyIndex = 0;
for (const key in posts.val()) {
keyIndex++;
if(val[key][postId] != undefined) {
found = true;
//do something
} else {
if (keyIndex === totalKeyCount) {
console.log('last iteration');
}
}
}
But, if you don't depend on inherited keys, it would be better to use Object.keys, which returns an array, and upon which array methods can be used.
Assuming you're trying to find a particular value in the object (and on the object itself), you can use .find on Object.values instead:
const foundPost = Object.values(posts.val()).find(item => item[postId] !== undefined);
// if an item[postId], if it exists, will be truthy, simplify to `item => item[postId]`
if (foundPost) {
// do something with the found post
} else {
// all iterations have been completed, and nothing was found
}
Also note that the order of properties iterated on in a for..in loop is not entirely reliable. As MDN says:
A for...in loop iterates over the properties of an object in an arbitrary order (see the delete operator for more on why one cannot depend on the seeming orderliness of iteration, at least in a cross-browser setting).
There's no real notion of end of an object unless you mean the last key to iterate. You can get the object's keys, iterate, and check the index against keys.length-1:
let obj = posts.val();
Object.keys(obj).forEach((k, i, keys) => {
if(obj[k][postId] !== undefined) {
let found = true;
//do something
} else {
let atEnd = (i === keys.length-1);
// if at end && found !== true
}
});
Typically, finding something looks like this:
function isFound(obj, cmpFn) {
let found = false;
for (let k in obj) {
if (cmpFn(obj[k]) === true) {
found = true;
break;
}
}
return found;
}
Or:
function isFound(obj, cmpFn) {
return Object.keys(obj)
.some(k => cmpFn(obj[k]));
}
You should have both keys somewhere, so you can avoid iteration entirely:
let isFound = (id_b in obj[id_a]);
The above works if you don't store empty entries in the table, which is usually desirable.
I'd also recommend using !== over != to avoid coercion and ambiguity.
I am trying to understand how recursive work with a nested js object which may have same key name. For example in the below object the keys are same in nest.
So when I am looping I am expecting obj[keys] will always go the first line(marked as //Line 1).
I am trying to understand how js will know consider which nest to loop if all the keys have same name. Not sure where I am going wrong in understanding
var obj = {
a: { // Line 1
a: { // Line 2
a: { // Line 3
sweptArea: 5
}
}
}
}
function loop(obj, keyName) {
for (var keys in obj) {
if (obj.hasOwnProperty(keys) && typeof obj[keys] === 'object') {
if (obj[keys][keyName] !== undefined) {
console.log(obj[keys][keyName])
} else {
// In my understanding in all the iteration it will point to obj.a marked as line one
loop(obj[keys], 'sweptArea')
}
}
}
}
loop(obj, 'sweptArea')
When you say obj[keys] is only looks for a key of that name on obj. That expression, by itself, does no recursion.
The value passed to the variable defined to the obj argument is different each time the function is called.
I found myself in an interesting situation. I am using an object literal to represent a product in the real-world. Now each product has a length associated to it for shipping purposes. It looks something like this:
var product = {
name: 'MacBook Pro 15 Inch',
description: 'The new macbook pros....',
length: 15
height: 15
Weight: 4
}
This this works fine. But for products that have unknown length they default to length -1.
Again this works fine, until you try to do this:
console.log('Product has the following properties');
_.each(product, function(val, key) {
console.log(key + ":" + val);
});
No keys will be printed for a product that has a length of -1. Why? Well because internally underscore uses the length attribute, that every object in Javascript has to loop over all the attributes of the passed in object. Since we overwrote that value, it is now -1, and since we start looping at i = 0, the loop will never be executed.
Now for the question, how can I prevent the length property from being overridden? Best practices to prevent this from happening would also be appreciated.
try this:
var product = {
name: "MacBook Pro 15 Inch",
description: 'The new macbook pros....',
length: 15,
height: 15,
weight: 4
};
console.log('Product has the following properties');
_.each(_.keys(product), function(key){
console.log(key + ":" + product[key]);
});
This is perhaps due to some magic in _'s each function as I suspect it accepts both Objects and Arrays .. make your own?
Simple implementation (that avoids some common pitfalls):
function each(obj, map_func) {
var key;
for (key in obj) {
if (Object.prototype.hasOwnerProperty.call(obj, key)) {
map_func(key, obj[key]);
}
}
}
The magic in _'s each is probably due a nasty 'habit' in JavaScript of having things that 'look' like Arrays but aren't actually Arrays, like the magical variable arguments, and I think options in a select DOM Elements as well.
I can't think of anything off-hand that overrides it. I suppose using the length property is a form of duck typing that marks it by jQuery as iterable.
But.. you can just not use the jQuery each method, and do it the manual way..
By simply using
for (key in product) {
}
You get your basic loop. Now if you are potentially overriding the object's prototype, you should also check product.hashOwnProperty(key) to make sure the current key you're iterating is defined in the product instance.
Now if you also need a new closure scope, that's pretty simple too.. here's an alternative each function..
var myEach = function(subject, callback) {
for (key in subject) {
if (subject.hasOwnProperty(key)) {
callback(subject[key], key);
}
}
}
Note: untested.
If you can't change the name of the length property, you could add an additional check to underscore to prevent this case:
_.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length && obj.constructor != Object) {
for (var i = 0, l = obj.length; i < l; i++) {
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (_.has(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};
The addition here is the && obj.constructor != Object on line 5. It works, though monkeypatching underscore may not be the most desirable thing in the world.
EDIT: Actually, this breaks on pseudo-arrays like arguments, since its constructor is Object, but <an array-like object>.hasOwnProperty(<an integer>) is false. Woo JavaScript.
My question is based on and similar to this one but a little bit different because property name will be variable.
How do I create a function which will return me index of object having certain value of provided property?
function indexOf(propertyName,lookingForValue,array){
//......
return index;
}
So,
indexOf("token",123123,[
{id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]);
should return 1.
The main problem I have is how do I check the property value when I have the property name as string with me?
function indexOf(propertyName,lookingForValue,array) {
for (var i in array) {
if (array[i][propertyName] == lookingForValue) {
return i;
}
}
return undefined;
}
Edit: Please note that I do the loose type check '==' on purpose since you are giving an integer to this function whereas in the array the value you search for is a string.
I make a function which can be helpful to you. Check it.
function GetindexOf(propertyName,lookingForValue,array){
var obj = array;
for(o in obj)
{
if(obj[o][propertyName] == lookingForValue)
{
//return index;
alert("You have request for "+o+" index");
}
}
}