66

I have an object

currentValues= {hey:1212, git:1212, nmo:12121}

and I use for in like this:

for (const key in currentValues) {
    if (Object.prototype.hasOwnProperty.call(currentValues, key)) {
        yield put(setCurrentValue(key, currentValues[key]));
    }
}

ESLint shows me an error which is saying:

ESLint: for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array. (no-restricted-syntax

How should I edit my code?

6
  • 2
    Try for(const key of currentValues.keys()) if you only need the keys. You can use entries if you need the keys and values. Commented May 5, 2017 at 14:29
  • @AndrewLi are you talking about Object.keys()? If so, it'd stiill be questionable, since iterating through an array with for ... in is frowned upon. Commented May 5, 2017 at 14:30
  • 1
    @Pointy I'm using for...of? Commented May 5, 2017 at 14:31
  • Oops sorry, carry on :) But still; there's no .keys() function on that object. Commented May 5, 2017 at 14:31
  • 2
    If for in was terrible, why can't they deprecate it 😡 Commented Jan 12, 2020 at 13:37

8 Answers 8

88

It says,

Use Object.{keys,values,entries}, and iterate over the resulting array.

So you could do something like this to get the object keys as an array and then loop through the keys to make necessary changes.

currentValues= {hey:1212, git:1212, nmo:12121}

Object.keys(currentValues).forEach(function(key) {
  yield put(setCurrentValue(key, currentValues[key]));
})

Sign up to request clarification or add additional context in comments.

4 Comments

yea, but I do not understand why? It could be really a problem?
How can this be any more intuitive or short than a plain old for in?
@Jonny for..in will loop through the whole prototype chain as the ESLint message explains, so you end up getting unexpected items in your loop. To avoid this, people would add an if (Object.prototype.hasOwnProperty.call...) inside the for..in loop (see OP code sample). Using Object.keys eliminates the need for this if inside for..in, it's much cleaner and straightforward than using for..in.
A 'yield' expression is only allowed in a generator body
14

I used the following:

const keys = Object.keys(currentValues);
const values = Object.values(currentValues);
for (let i = 0; i < keys.length; i += 1) {
    yield put(setCurrentValue(keys[i], values[i]));
}

This is correct and without ESLint errors.

Comments

6

I would do it by refactoring, in the following ways.

const currentValues = { hey: 1212, git: 1212, nmo: 12121 };

Object.keys(currentValues).forEach((e) => console.log(`${e} : ${currentValues[e]}`));

Results:

hey : 1212 git : 1212 nmo : 12121

Object.values(currentValues).forEach((e) => console.log(`Values: ${e}`));

Results:

(2)Values: 1212 Values: 12121

Object.entries(currentValues).forEach((e) => console.log(`${e[0]} : ${e[1]}`));

Results:

hey : 1212 git : 1212 nmo : 12121

Comments

4

You can get the array of all your values inside your object just doing

var myValuesInArray = Object.values(currentValues);

Comments

4

let animal = {
  eats: "Eating",
};
let rabbit = {
  jumps: "Jumping",
};

rabbit.__proto__ = animal;

for (const rabbitProps in rabbit) {
  // This will print both eats and jumps properties because they're part of
  // prototype chain
  console.log("rabbitProps: ", rabbitProps);
}

// This prints only jumps as Object.keys shows only the keys of object
console.log(Object.keys(rabbit));

Checking out the above code you can see that when using for...in loop[ it will show all the properties that are part of object as well as properties set in the prototype chain of the object and so eslint suggests to use Object.keys or value or entries, as they do not look into prototype chain instead they just look at your object.

Comments

3

I know it is similar to the above, but here is a full example:

const data = res.data;
const keys = Object.keys(data);
const values = Object.values(data);

for (let i = 0; i <= keys.length; i += 1) {
  if (Object.prototype.hasOwnProperty.call(values, i)) {
     this.rows.push({
        name: values[i].name,
        email: values[i].email,
        address: values[i].address,
        phone: values[i].phone,
        role: values[i].role,
  });
 }
}

1 Comment

hasOwnProperty is not required if using Object.keys(): stackoverflow.com/questions/29004314/…
2

try this instead:

Object.keys(currentValues).map(key => (yield put(setCurrentValue(key, currentValues[key]))));

Comments

0

Using for...in will iterate over all properties including those from Object prototype. I am not sure why you are doing Object.prototype.hasOwnProperty.call(currentValues, key) instead of just: currentValues.hasOwnProperty(key). I think this should make ESLint aware that you are filtering for own properties only.

However, I suggest using for (const key of Object.keys()), which is more semantic.

1 Comment

using hasOwnPrototype(..) from Object is better. see eslint.org/docs/rules/no-prototype-builtins

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.