Pregunta de la entrevista 2: hable sobre su comprensión de for in y for of en JavaScript

para en

for...in La declaración itera sobre las propiedades enumerables de un objeto distintas de Símbolo en cualquier orden , incluidas las propiedades enumerables heredadas.

Antes de tener una comprensión profunda del papel de for in, solo me quedé en el nivel en el que puede atravesar claves de objetos y subíndices de matrices. Ahora exploremos qué es una clave de tipo Símbolo en un objeto (recién agregada después de ES6) y propiedades enumerables. ,

Los tipos de objetos en JS incluyen Objeto, Matriz, Función, Fecha, Matemáticas....

Este artículo utiliza principalmente Object y Array para practicar.

Primero, veamos un fragmento de código:

const arr = [5, 4, 3, 2, 1];
 
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);
}
 

Creo que todos tienen muy claro los resultados de salida. Si atraviesa una matriz, se genera el subíndice correspondiente a la matriz. Si se atraviesa un objeto, se genera el nombre clave del objeto.

Continúe aumentando la dificultad y observe el siguiente código:

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
}
 
 

Como se puede ver en el resultado anterior, ya sea un elemento de matriz o un valor clave en un objeto, todos son atributos enumerables, y se puede ver que aunque la clave de tipo Símbolo está definida en el objeto, for in se saltará el tipo de símbolo.

Y porque in también atravesará la cadena de prototipos, entonces, ¿por qué genera 'myProto' cuando atraviesa obj y arr? Eso es porque obj es un objeto, el constructor predeterminado es Object() y arr es un objeto de matriz, el constructor predeterminado es Array (), pero el atributo prototipo de Array es esencialmente un objeto, por lo que el prototipo del prototipo de Array es el atributo prototipo de Objeto.
 

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

Por lo tanto, las cadenas prototipo de arr y obj tienen una intersección, lo que explica que ambas pueden atravesar myProto.

También podemos simplemente pensar que la propiedad correspondiente a la clave de tipo Símbolo en un objeto no es una propiedad enumerable, pero en realidad sigue siendo una propiedad enumerable, simplemente omitida. Este párrafo es un poco complicado, pero en el pasado será claro cuando miras hacia abajo.

Dado que el recorrido de for in no puede evitar atributos enumerables, ¿qué son los atributos enumerables? La explicación de MDN es la siguiente:
 

Las propiedades enumerables se refieren a aquellas propiedades cuyo indicador interno "enumerable" está establecido en verdadero. Para las propiedades mediante asignación directa e inicialización de propiedad, el valor de identificación predeterminado es verdadero. Para las propiedades definidas a través de Object.defineProperty, etc., el valor predeterminado de este indicador es falso . Las propiedades enumerables se pueden recorrer a través de un bucle for...in (a menos que el nombre de la propiedad sea un símbolo). La propiedad de una propiedad se determina determinando si la propiedad pertenece directamente a un objeto, en lugar de heredarse a través de la cadena de prototipos.

De lo anterior se puede concluir que

Las propiedades enumerables son aquellas propiedades con el indicador "enumerable" establecido en verdadero dentro del objeto. Para las propiedades
definidas mediante literales, el indicador enumerable por defecto es verdadero. Para las propiedades definidas a través de Object.defineProperty, etc., el indicador predeterminado es flase
para The in El bucle solo atravesará los atributos enumerables en el objeto y omitirá los atributos cuyos nombres de atributos sean tipos de símbolo.
for in solo atravesará los atributos enumerables en el objeto mismo
. Consulte el siguiente código:
 

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
}
 

 

 

En el código anterior, primero creamos un objeto obj con una marca de atributo de inicialización, luego definimos dos nuevas propiedades a través de literales y definimos valores clave de 2 tipos de cadena y 2 de tipo símbolo a través de Object.defineProperty, cada uno de los cuales tiene un enumerable. e identificador no enumerable

Puede ver que console.log imprime obj, que solo contiene atributos enumerables, es decir, los atributos cuyo indicador enumerable es falso no aparecerán en el contenido impreso de todo el objeto obj, lo que también verifica que incluso si el tipo de símbolo key El atributo se puede enumerar y marcar como verdadero, que también se omitirá en.
Ampliación adicional

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
}

Puede ver que el subíndice de la matriz también es un atributo del objeto de la matriz. Después de configurar el subíndice 0 como no enumerable y no modificable, porque no puede atravesar el subíndice 0 y no puede modificar el valor del subíndice 0, pero la diversión Lo importante es imprimir. La matriz seguirá imprimiendo cada elemento en su totalidad.

para de 

for...ofLa declaración crea un bucle de iteración sobre un objeto iterable (incluidos  Array , Map , Set , String , TypedArray , objetos de argumentos  y más), llama a un enlace de iteración personalizado y ejecuta la declaración para cada valor de propiedad distinto.

for of es una nueva sintaxis en ES6 para atravesar objetos iterables (implementando la interfaz Iterator )

// 迭代数组
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
}

 Cerrar iterador

Para for...ofun bucle, puede terminar con  breakthrow o  return . En estos casos, el iterador está cerrado.

situación de retorno

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); 
}

 situación de lanzamiento

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); 
}

Para for...inbucles, el método de interrupción anterior también se aplica

El resumen
para...in es adecuado para atravesar propiedades enumerables en objetos, y solo atraviesa claves que no son de tipo símbolo y el objeto en sí y propiedades enumerables en la cadena de prototipo. for... of es adecuado
para objetos que implementan la interfaz Iterator ( También conocido como objeto iterable), el método transversal se implementa por sí mismo, por ejemplo, para una matriz, atraviesa el valor del elemento correspondiente a cada subíndice, y para un mapa, el valor transversal es una matriz compuesta por clave-valor. pares.
 

Queridas celebridades, denme el visto bueno y apoyen, ¡gracias! ! !

Supongo que te gusta

Origin blog.csdn.net/2201_75705263/article/details/132816326
Recomendado
Clasificación