当对象是JSON对象时,[For.. in]循环中使用的变量返回不同的值,而当对象是数组对象时又返回不同的值。

12 浏览
0 Comments

当对象是JSON对象时,[For.. in]循环中使用的变量返回不同的值,而当对象是数组对象时又返回不同的值。

我将这个问题分成两个子部分,因为它们相关,并且这样更容易理解。

现在,我们有一个数组,并且变量p会遍历所有属性,这里是数组的项,并将项的索引号赋给它自己。所以,1..2..3。这样我可以做下面的事情:

..使用变量p作为一个数值子字符串,返回每个数组项的属性名。

现在,这里有两个问题:

1. 如果变量遍历属性,就像它的描述说的那样,那么为什么在数组上使用它时,变量会赋予项的索引数值?

2. 为什么使用outside[number]返回属性的名称?

一个解释是,每个数组项实际上是一个对象,显然子字符串[number]返回该对象的名称,而for..in变量遍历数组项对象的每个属性,而它们的属性实际上是索引号,所以它返回的就是索引号。

这个解释是正确的,还是完全错误的?

我问题的第二部分是关于使用JSON对象。

现在,变量i返回对象的属性名。

然而,像之前数组那样使用变量i作为一个子字符串,返回的是属性的值。

现在,这里也有两个问题:

1. 为什么[i]表示属性的位置,因为[i]不是一个数值?

2. 为什么maryobject[i]返回属性的值?

0
0 Comments

在 JavaScript 中,Array 和解析后的 JSON 对象(甚至函数)在某种程度上都是对象。可以使用数字名称来定义对象的属性,但它们不是有效的 JSON。下面的示例演示了这一点:

var o = {
  0: "a"
};
var s = '{0:"a"}';
console.log(JSON.stringify(o));
console.log(JSON.parse(JSON.stringify(o)));
try {
  console.log(JSON.parse(s));
} catch (error) {
  console.log(error.message);
}

如果在开发者工具的控制台中打开此页面,你会看到解析字符串化对象的那一行输出为`{0: "a"}`,与代码片段的结果不同,后者将解析的属性名称视为字符串。这是因为 V8 引擎的解析结果,这不是一个可以依赖的标准。

所以你可以看到,控制台显示的是 JavaScript 引擎解释的结果。在标准中,array(小写)和Array(大写)是两个不同的概念。但是 JavaScript 的解释器和引擎有时会按照它们认为最好的方式进行解释。

对于这个问题,for...in 循环遍历对象的可枚举属性,在旧版本中(或不同的引擎)可能会收到某种类型的错误,因为正确遍历array(小写)的方式是使用for(i=0; i<a.length; i++)。现在,随着对象化的 Array 出现,遍历这些对象值的正确方式可以说是使用 Array.prototype.forEach()for...of

"Given that for...in is built for iterating object properties, not recommended for use with arrays, and options like Array.prototype.forEach() and for...of exist, what might be the use of for...in at all?"

你也可以在这里阅读更多关于对象及其属性的可枚举性、可迭代性和所有权的信息。

最后,如果你想要定义一个没有默认行为的属性,可以使用Object.defineProperty()来定义,例如:

var o = {};
Object.defineProperty(o, "first_name", {
  value: "John",
  writable: false,
  enumerable: false,
  configurable: true
});
Object.defineProperty(o, "last_name", {
  value: "Doe",
  writable: false,
  enumerable: false,
  configurable: true
});
Object.defineProperty(o, "name", {
  enumerable: true,
  configurable: false,
  get() {
    return `${this.first_name} ${this.last_name}`;
  },
  set(value) {
    let [first_name, last_name] = value?.split(' ') ?? ["N/A", "N/A"];
    Object.defineProperty(this, "first_name", {
      value: first_name
    });
    Object.defineProperty(this, "last_name", {
      value: last_name
    });
  }
});
console.table({
  "first_name": o.first_name,
  "last_name": o.last_name,
  "name": o.name
});
for (let i in o) {
  console.log(`${i}:`, o[i]);
}
o.name = "No way";
console.table({
  "first_name": o.first_name,
  "last_name": o.last_name,
  "name": o.name
});
for (let i in o) {
  console.log(`${i}:`, o[i]);
}

以上就是为什么在使用 for...in 循环时,当对象是 JSON 对象时与数组对象返回不同值的原因以及解决方法。

0
0 Comments

问题出现的原因是,在for...in循环中,当对象是一个JSON对象时,循环变量返回的是字符串类型的属性名;而当对象是一个数组对象时,循环变量返回的是数字类型的索引。

解决方法是,在for...in循环中,可以使用额外的变量来保存属性名或索引,并在循环体内部使用该变量访问对象的属性或元素。

以下是整理后的文章:

数组是具有伪数值属性的对象。这是一种看待它的方式。看看下面的例子:

const a = ['neat', 'no', 'not', 'really'];
console.log(a['0']);
console.log(typeof a);
console.log(a instanceof Array);
console.log('-'.repeat(50));
for(let i in a){
  console.log(typeof i);
}
const o = {0:'I', nice:"can't'", prop:'believe', 3:'this', key:'is a question'};
console.log('-'.repeat(50));
console.log(o[0]);
console.log(typeof o);
console.log(o instanceof Array);
console.log('-'.repeat(50));
for(let p in o){
  console.log(typeof p);
}

注意,在这个例子中,你可以使用数字索引来访问对象。对象实际上使用字符串属性。当使用数字属性时,它们会将其转换为字符串。在`for(let prop in obj)`中,`prop`是实际的属性值,它是一个字符串。是的,将循环变量的作用域限制在循环内部也是一个好主意。

因此,当使用`for...in`循环遍历JSON对象时,循环变量返回的是字符串类型的属性名。而当使用`for...in`循环遍历数组对象时,循环变量返回的是数字类型的索引。如果想要在循环体内部访问具体的属性或元素,可以使用额外的变量来保存属性名或索引。

0
0 Comments

为什么在[For..in]循环中,当对象是JSON对象时,使用的变量返回不同的值,而当对象是数组对象时,返回不同的值?

这个问题的出现是因为在JavaScript中,数组和对象是两种不同的数据类型,它们在内部的数据结构和对属性的处理方式上存在差异。

首先,根据ECMAScript规范,对象是由属性构成的集合,属性使用键值来进行标识。属性的键值可以是字符串或符号类型,而属性名是指键值为字符串类型的属性。

而数组是一种特殊的对象,它对数组索引属性键进行了特殊处理。数组索引是指数值范围在0到2^32-1之间的整数索引。因此,数组可以看作是一种优化了的属性名为数值型索引的对象。

换句话说,数组可以用对象的形式表示,例如:

a = [4];

可以等价于

a = {'0': 4};

尽管它们在原型和内部实现上有所不同。

对于对象和数组,我们可以通过属性访问表达式来获取属性的值。例如,a[b]会返回对象a中属性名为b的属性的值。这对于对象和数组都是适用的。

为什么在数组中使用变量时,变量会被赋予索引的数值?

正如我们所学到的,数组是一种属性名为数值型索引的对象。因此,在数组中使用变量作为属性访问表达式时,变量被解析为索引的数值,并返回对应的属性值。

为什么在使用outside[number]时返回属性的名称?

上述的属性访问表达式a[b]会返回属性名为b的属性的值。因此,当使用数组时,a[0]和a['0']都会返回属性名为'0'的属性值。这是因为ECMAScript在需要时会自动将数值转换为字符串,以便匹配属性名。

为什么[i]表示属性的位置,而[i]不是数值?

[i]并不表示属性的位置,[i]是一个属性访问表达式,它访问属性名与i的值相等的属性的值。由于属性名是字符串(或符号),因此运行时环境会根据属性名查找相应的内存地址。具体的实现方式由运行时环境决定,只要结果是正确的即可。

当然,现代的JavaScript运行时环境会将a[i]转换为直接的内存访问,前提是a是一个数组且i是一个数值(当然还要进行适当的边界检查)。但是,运行时环境也必须处理i是任意字符串(或符号)的情况。

当使用[For..in]循环遍历对象时,对于数组和JSON对象,变量的值和属性的访问方式存在差异。了解这些差异可以帮助我们更好地理解JavaScript中的对象和数组的特性,并正确地使用它们。

0