Pergunta 2 da entrevista: Fale sobre sua compreensão de for in e for of em JavaScript

para dentro

for...in A instrução itera sobre as propriedades enumeráveis ​​de um objeto , exceto Symbol , em qualquer ordem , incluindo propriedades enumeráveis ​​herdadas.

Antes de ter uma compreensão profunda do papel do for in, fiquei apenas no nível em que ele pode percorrer chaves de objeto e subscritos de array. Agora vamos explorar o que é uma chave do tipo Símbolo em um objeto (recém-adicionada após ES6) e propriedades enumeráveis ,

Os tipos de objetos em JS incluem Objeto, Matriz, Função, Data, Matemática....

Este artigo usa principalmente Object e Array para prática.

Primeiro, vamos dar uma olhada em um trecho 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);
}
 

Acho que todos estão muito claros sobre os resultados de saída. Se estiver percorrendo um array, o subscrito correspondente ao array será gerado. Se estiver percorrendo um objeto, o nome da chave do objeto será gerado.

Continue aumentando a dificuldade e observe o seguinte 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 pode ser visto na saída acima, seja um elemento de array ou um valor-chave em um objeto, todas são propriedades enumeráveis, e pode-se ver que embora a chave do tipo Símbolo seja definida no objeto, for in irá pular o tipo de símbolo. passagem de chave

E for in também percorrerá a cadeia de protótipos, então por que ele produz 'myProto' ao percorrer obj e arr?Isso ocorre porque obj é um objeto, o construtor padrão é Object () e arr é um objeto de array, o construtor padrão é Array(), mas o atributo protótipo de Array é essencialmente um objeto, então o protótipo do protótipo Array é o atributo protótipo em Objeto.
 

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

Portanto, as cadeias de protótipos de arr e obj possuem uma interseção, o que explica que ambas podem atravessar para myProto.

Também podemos simplesmente pensar que a propriedade correspondente à chave do tipo Símbolo em um objeto não é uma propriedade enumerável, mas na verdade ainda é uma propriedade enumerável, apenas ignorada.Este parágrafo é um pouco complicado, mas no passado será claro quando você olha para baixo.

Como a travessia de for in não pode evitar atributos enumeráveis, o que são atributos enumeráveis? A explicação do MDN é a seguinte:
 

Propriedades enumeráveis ​​referem-se às propriedades cujo sinalizador interno "enumerável" é definido como verdadeiro. Para propriedades por meio de atribuição direta e inicialização de propriedade, o valor de identificação é padronizado como verdadeiro. Para propriedades definidas por meio de Object.defineProperty, etc., esse valor de sinalizador é padronizado como falso . Propriedades enumeráveis ​​podem ser percorridas através de um loop for...in (a menos que o nome da propriedade seja um Símbolo). A propriedade de uma propriedade é determinada determinando se a propriedade pertence diretamente a um objeto, em vez de ser herdada através da cadeia de protótipos.

Pode-se concluir do exposto que

Propriedades enumeráveis ​​são aquelas propriedades com o sinalizador "enumerável" definido como verdadeiro dentro do objeto. Para propriedades
definidas por meio de literais, o sinalizador enumerável é padronizado como verdadeiro. Para propriedades definidas por meio de Object.defineProperty, etc., o sinalizador é padronizado como flase
para The in loop percorrerá apenas os atributos enumeráveis ​​no objeto e ignorará os atributos cujos nomes de atributos são do tipo Símbolo.
for in percorrerá apenas os atributos enumeráveis ​​no próprio objeto
. Consulte o código a seguir:
 

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
}
 

 

 

No código acima, primeiro criamos um objeto obj com uma marca de atributo de inicialização, em seguida, definimos duas novas propriedades por meio de literais e definimos 2 valores-chave de tipo de string e 2 valores de chave de tipo de símbolo por meio de Object.defineProperty, ambos os quais Cada um tem um enumerável e identificador não enumerável

Você pode ver que console.log imprime obj, que contém apenas atributos enumeráveis, ou seja, os atributos cujo sinalizador enumerável é falso não aparecerão no conteúdo impresso de todo o objeto obj, o que também verifica se mesmo que o tipo Símbolo chave O atributo pode ser enumerado e marcado como verdadeiro, o que também será ignorado por in.
Expansão 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
}

Você pode ver que o subscrito da matriz também é um atributo do objeto da matriz. Depois de definir o subscrito 0 como não enumerável e não modificável, pois in não pode percorrer o subscrito 0 e não pode modificar o valor do subscrito 0, mas a diversão o importante é imprimir O array ainda imprimirá cada elemento por completo.

para de 

for...ofA instrução cria um loop de iteração sobre um objeto iterável (incluindo  Array , Map , Set , String , TypedArray ,  objetos de argumentos e muito mais), chama um gancho de iteração personalizado e executa a instrução para cada valor de propriedade distinto

for of é uma nova sintaxe no ES6 para percorrer objetos iteráveis ​​(implementando a interface 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
}

 Fechar iterador

Para for...ofum loop, ele pode ser finalizado com  breakthrow ou  return . Nestes casos, o iterador é fechado.

situação 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); 
}

 situação de lançamento

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...inloops, o método de interrupção acima também se aplica

Resumo
for...in é adequado para percorrer propriedades enumeráveis ​​em objetos e apenas percorre chaves do tipo não-Symbol e o próprio objeto e propriedades enumeráveis ​​na cadeia de protótipos. for... of é adequado para
objetos que implementam a interface Iterator ( Também conhecidos como objetos iteráveis), o método de travessia é implementado por si só. Por exemplo, para um array, ele percorre o valor do elemento correspondente a cada subscrito, e para um Mapa, o valor de travessia é um array composto de valor-chave pares.
 

Queridas celebridades, dêem-me um joinha e apoio, obrigado! ! !

Acho que você gosta

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