[Interview Question] Understanding of for in and for of in JavaScript

 Front-end interview question bank ( necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

for in

MDN description:

for...in statement iterates over an object 's enumerable properties other than Symbol , including inherited enumerable properties, in any order.

Before I have a deep understanding of the role of for in, I only stay at the level where it can traverse object keys and array subscripts. Now let’s explore what is a Symbol type key in an object (newly added after ES6) and enumerable properties ,

Object types in JS include Object, Array, Function, Date, Math....

This article mainly uses Object and Array for practice

First, let's look at a piece of code:

const arr = [1, 2, 3, 4, 5];

const obj = {
  mark: "mark-v",
  jack: "jack-v",
  amy: "amy-v",
};

for (const i in arr) {  // 输出 0 1 2 3 4
  console.log(i);
}

for (const i in obj) { // 输出 mark jack amy
  console.log(i);
}

Presumably everyone knows the output result very well. If it is traversing the array, output the subscript corresponding to the array, and if it is traversing the object, output the key name of the object

Continue to add dishes, and then look at the following code:

const arr = [1, 2, 3, 4, 5];

arr.value = "array"; // 给数组对象上添加一个value属性

const s1 = Symbol("symbol1"); // 定义两个symbo类型的值
const s2 = Symbol("symbol2");

const obj = {
  mark: "mark-v",
  jack: "jack-v",
  amy: "amy-v",
  [s1]: "symbol1-v", // 给obj初始化这两个symbol键值
  [s2]: "symbol2-v",
};

// 给obj原型上添加一个属性
Object.getPrototypeOf(obj).myProto = 'proto'

console.log(obj);
// 打印 {
//  mark: 'mark-v',
//  jack: 'jack-v',
//  amy: 'amy-v',
//  [Symbol(symbol1)]: 'symbol1-v',
//  [Symbol(symbol2)]: 'symbol2-v'
// }

for (const i in arr) {
  console.log(i); // 输出 0 1 2 3 4 value myProto
}

for (const i in obj) {
  console.log(i); // 输出 mark jack amy myProto
}


As can be seen from the above output results, whether it is an array element or a key value on an object, it is an enumerable attribute , and it can be seen that the key of the Symbol type is defined in the object, but for in will skip the Symbol type key traversal

And for in will also traverse the prototype chain , so why both obj and arr will output 'myProto', that is because obj is an object, the default constructor is Object(), and arr is an array object, the default The constructor is Array(), but the prototype property of Array is essentially an object, so the prototype of the Array prototype is the prototype property on Object

Object.getPrototypeOf(obj) === Object.getPrototypeOf(Object.getPrototypeOf(arr)) // true

So the prototype chains of arr and obj have an intersection point, which explains that they can all traverse to myProto

We can also simply think that the attribute corresponding to the Symbol type key in an object is not an enumerable attribute, but in fact it is still an enumerable attribute, but it is skipped. This passage is a bit confusing, but in the past It will be clear when you look down.

Since the traversal of for in cannot bypass enumerable attributes, what is an enumerable attribute? The explanation of MDN is as follows:

Enumerable properties refer to those properties whose internal "enumerable" flag is set to  true . For properties through direct assignment and property initialization, the flag value defaults to that  true. For   properties defined through Object.defineProperty , etc., the flag The value defaults to  false. Enumerable properties can   be traversed  through a for...in loop (unless the property name is a Symbol ). Property ownership is determined by judging whether the property directly belongs to an object, rather than being inherited through the prototype chain.

From the above it can be concluded that,

  1. Enumerable properties are those inside an object that have the "enumerable" flag set to true
  2. For properties defined by literals, the enumerable flag defaults to true, and for properties defined by Object.defineProperty, etc., the flag defaults to flase
  3. The for in loop only traverses the enumerable properties in the object, and skips properties whose property names are of type Symbol
  4. for in will only traverse the enumerable properties on the object itself

Please see the following code:

const s1 = Symbol("symbol1");
const s2 = Symbol("symbol2");
// 以下字面量初始化和赋值的属性可枚举标识都为true
const obj = {          // 方式一
  mark: "mark-v",
};
obj.jack = "jack-v"     // 方式二
obj['amy'] = 'amy-v'    // 方式三

Object.defineProperty(obj, "kong", {
  value: "kong-v",
  enumerable: false,   // 可枚举标识,默认为 false
});

Object.defineProperty(obj, "john", {
  value: "john-v",
  enumerable: true,   // 设置为 true
});
// 通过Object.defineProperty设置Symbol类型键
Object.defineProperty(obj, s1, {
  value: "s1-v",
  enumerable: false,   
});
// 通过Object.defineProperty设置Symbol类型键,并且可枚举标识为true
Object.defineProperty(obj, s2, {
  value: "s2-v",
  enumerable: true,
});

console.log(obj);
// 打印 {
//   mark: 'mark-v',
//   jack: 'jack-v',
//   amy: 'amy-v',
//   john: 'john-v',
//   [Symbol(symbol2)]: 's2-v'
// }

for (const i in obj) {
  console.log(i);     // 输出 mark jack amy john
}

In the above code, we first created an obj object with an initialization property mark, then defined two new properties through literals, and defined 2 key values ​​of string type and 2 symbol types through Object.defineProperty, both Each has an enumerable and non-enumerable identifier

You can see that the console.log prints obj, which only contains enumerable attributes, that is to say, the attribute whose enumerable flag is false will not appear in the printed content of the entire obj object, which also verifies that even if the Symbol type key The attribute can be enumerated as true, and it will also be skipped by for in.

Additional expansion

const arr = [1, 2, 3, 4, 5];
// 设置arr对象属性0的值为100,不可枚举,不可修改
Object.defineProperty(arr, 0, {
  value: 100,
  enumerable: false,
  writable: false,
});

arr[0] = 1 // 尝试修改下标0的值

console.log(arr);  // 打印 [ 100, 2, 3, 4, 5 ]

for (const i in arr) {
  console.log(i);    // 输出 1 2 3 4
}

You can see that the subscript of the array is also an attribute of the array object. After setting the subscript 0 to be non-enumerable and non-modifiable, for in cannot traverse the subscript 0, and cannot modify the value of the subscript 0, but the fun thing is to print Arrays will still print out each element in its entirety.

for of

MDN description:

for...ofThe statement creates an iteration loop over iterable objects (including  Array , Map , Set , String , TypedArray , arguments  objects, etc.), calls custom iteration hooks, and executes the statement for the value of each distinct property

for of is a new ES6 syntax for traversing iterable objects (implementing the Iterator interface)

example

// 迭代数组
const array = [10, 20, 30];
for (const value of array) {
    console.log(value); // 输出 10 20 30
}

// 迭代String
const string = 'kong'
for (const s of string) {
    console.log(s); // 输出 k o n g
}

// 迭代map
const map = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (const item of map) {
  console.log(item);  // 输出  [ 'a', 1 ]  [ 'b', 2 ]  [ 'c', 3 ]
}

// 迭代set
const set = new Set([1, 1, 2, 2, 3, 3]);
for (let item of set) {
  console.log(item);  // 输出 1 2 3
}

close iterator

For for...ofloops, it can be terminated by  breakthrow or  return . In these cases, the iterator is closed.

return situation

const array = [10, 20, 30];
for (const value of array) {
    console.log(value); // 输出 10
    return
}
// 下面代码不会执行,前面已经return
const string = 'kong'
for (const s of string) {
    console.log(s); 
}

Throw situation

const array = [10, 20, 30];
for (const value of array) {
  console.log(value); // 输出 10
  throw new Error()
}
// 不执行下面代码,上面已经抛错
const string = "kong";
for (const s of string) {
  console.log(s); 
}

For for...inthe loop, the above interrupt method is also applicable

Summarize

  • for...inApplicable to the traversal of enumerable properties on objects , and only traverse non-Symbol type keys and enumerable properties on the object itself and the prototype chain
  • for...ofApplicable to the traversal of objects (also known as iterable objects) that implement the Iterator interface . The traversal method is implemented by itself. For example, for an array, it is to traverse the value of each element corresponding to its subscript, and for a Map, the traversal value is composed of key-value pairs array of

 Front-end interview question bank ( necessary for interview) recommendation: ★★★★★            

Address: front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

Guess you like

Origin blog.csdn.net/weixin_42981560/article/details/132697783