ChatGPT解决这个技术问题 Extra ChatGPT

遍历对象属性

var obj = { 名称:“西蒙”,年龄:“20”,服装:{ 风格:“简单”,时髦:假 } } for(var propt in obj){ console.log(propt + ': ' + obj[道具]); }

变量 propt 如何表示对象的属性?它不是内置的方法或属性。为什么它会产生对象中的每个属性?

if (typeof(obj[propt]) === 'object') {/* 再做一次 */ }
好吧,真的很抱歉这个问题。我知道循环是什么,我无法理解“循环遍历对象属性”,我认为现在已经清除了。此外,他们还向我推荐了“JavaScript Step by Step 2nd Edition - Steve Suehring 在学校。
这是一个很好的初学者问题。我要补充一点,我有 15 年的其他语言专业经验,我需要这个答案。如果可以的话,我会加2000。
太疯狂了,但多年来我每隔几个月就会访问此页面,以重新学习有关如何执行此操作的语法。我不费心去记住如何做到这一点......我只记得这个页面总是在这里。
这是我在 StackOverflow 上看到的最奇怪的页面。如果您仔细阅读该问题,甚至只有一个答案开始尝试回答实际问题,并且得分为 -6。被接受的得分最高的答案不仅没有回答,而且完全是错误的。

L
Lambda Fairy

迭代属性需要额外的 hasOwnProperty 检查:

for (var prop in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        // do stuff
    }
}

这是必要的,因为对象的原型包含对象的附加属性,这些属性在技术上是对象的一部分。这些附加属性继承自基对象类,但仍然是 obj 的属性。

hasOwnProperty 只是检查这是否是特定于此类的属性,而不是从基类继承的属性。

也可以通过对象本身调用 hasOwnProperty

if (obj.hasOwnProperty(prop)) {
    // do stuff
}

但是如果对象有一个不相关的同名字段,这将失败:

var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

这就是为什么通过 Object.prototype 调用它更安全的原因:

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true

@BT 根据Mozilla documentation:“如果您只想考虑附加到对象本身的属性,而不是其原型,请使用 getOwnPropertyNames 或执行 hasOwnProperty 检查(也可以使用propertyIsEnumerable)。 "
调用 object.hasOwnProperty() 到底有什么意义? property 具有任何值这一事实是否意味着它在 object 中?
因为,Alex S,对象的原型包含对象的附加属性,这些属性在技术上是对象的一部分。它们是从基础对象类继承的,但它们仍然是属性。 hasOwnProperty 只是检查这是否是特定于此类的属性,而不是从基类继承的属性。一个很好的解释:brianflove.com/2013/09/05/javascripts-hasownproperty-method
然而,我觉得我应该提到 Object.keys(obj) 现在是获取对象本身键的更好的解决方案。 Mozilla 文档链接:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
缺少一项重要信息。 property 在这里是一个字符串,应该叫 propertyName。否则会对像我这样的 JS 新手造成混淆,即在 if 中做什么。
S
SetFreeByTruth

从 JavaScript 1.8.5 开始,您可以使用 Object.keys(obj) 获取在对象本身上定义的属性数组(对于 obj.hasOwnProperty(key) 返回 true 的属性)。

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

这比使用 for-in 循环更好(并且更具可读性)。

它在这些浏览器上受支持:

火狐(壁虎):4(2.0)

铬:5

互联网浏览器:9

有关详细信息,请参阅 the Mozilla Developer Network Object.keys()'s reference


如果您需要对旧浏览器的支持,您可以使用此polyfill
在支持此语言结构的环境中,此方法允许调用 Array.foreach:Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
@AJ_83 没有摆脱 forEach() 的好方法。在这种情况下使用 some() ,并返回 true 以中断
为什么这比 for-in 更具可读性? for candidate in candidateStatus... 对我来说似乎可读
F
Frank Roth

我们是 2019 年的女孩和男孩,我们没有那么多时间打字......所以让我们来做这个酷炫的新奇特 ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));

这与 Danny R 的回答有何不同?
它是一个单行器,使用 map 而不是 forEach。对于某些人来说,console.log 语句也可能很有趣。
Satly,当 obj=window.performance.memory :-/ Where as for in 时,这不起作用。即var obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
window.performance.memory 仅受 chrome 支持,Object.keys(obj) 返回一个空数组。这与 .map 无关。
万一有人不想在e 上重新构建这个单行程序以一次做不止一件事,我已经发布了这个要点。它基本上就像大多数哈希实现一样,使用 ( (key) => (value) ) 而不是 { key => value },但如果你还没有之前处理它,它可以帮助您更好地可视化它:gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
D
Dan Dascalescu

它是 for...in statementMDNECMAScript spec)。

您可以将其理解为“FOR 每个属性IN obj 对象,依次将每个属性分配给 PROPT 变量”。


非常感谢,我现在明白了。我在敲我的头,浏览书籍和谷歌。
同意@RightSaidFred,in 运算符和 for 语句根本不涉及,for-in statement 代表自己的语法产生:for ( LeftHandSideExpression in Expression )for ( var VariableDeclarationNoIn in Expression )
奇怪的是,这个答案有很多赞成票,特别是因为这些受欢迎的评论似乎与它相矛盾。
为什么这被标记为答案?这很可能是这个线程中最没有帮助的一个..
最没有帮助的答案?取决于您认为OP在问什么;当我第一次阅读这个问题时,它似乎对变量可用于检查对象属性的机制感到困惑困惑,并且这个答案雄辩地解释了这一点(尽管有“for-in”用词不当)。我看到的“为什么它会提供每个属性”的问题可能暗示 OP 正在寻找 hasOwnProperty 但不知道,但我认为这更有可能是 OP 想知道的,并且错误地接受了正确的回答一个不同的问题。 :-)
O
OneHoopyFrood

在 ES 的最新实现中,您可以使用 Object.entries

for (const [key, value] of Object.entries(obj)) { }

或者

Object.entries(obj).forEach(([key, value]) => ...)

如果您只想遍历这些值,请使用 Object.values:

for (const value of Object.values(obj)) { }

或者

Object.values(obj).forEach(value => ...)

这将是最好的解决方案(object.entries ...),但我不能使用它。当您想多次执行此操作并且在您的框架中无法支持时,您可以使用此页面上的 polyfill:developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
如果您只有属性的值,第三个建议很好。惊人的!
这是最佳答案,您应该使用 for (const [key, value] of Object.entries(obj)) { }
M
Matt Ball

这只是一个 for...in 循环。查看the documentation at Mozilla


链接已损坏:(。
@Burak 感谢您让我知道 - 已修复。将来,请随时提出修改建议:)
F
Fouad Boukredine
if (typeof obj === 'object' && obj !== null) {
    Object.keys(obj).forEach(key => {
        console.log("\n" + key + ": " + obj[key]);
    });
}

// *** Explanation line by line ***

// Explaining the bellow line
// It checks if obj is neither null nor undefined, which means it's safe to get its keys. 
// Otherwise it will give you a "TypeError: Cannot convert undefined or null to object" if obj is null or undefined.
// NOTE 1: You can use Object.hasOwnProperty() instead of Object.keys(obj).length
// NOTE 2: No need to check if obj is an array because it will work just fine.
// NOTE 3: No need to check if obj is a string because it will not pass the if typeof obj is Object statement.
// NOTE 4: No need to check if Obj is undefined because it will not pass the if type obj is Object statement either.
if (typeof obj === 'object' && obj !== null) {

    // Explaining the bellow line
    // Just like in the previous line, this returns an array with
    // all keys in obj (because if code execution got here, it means 
    // obj has keys.) 
    // Then just invoke built-in javascript forEach() to loop
    // over each key in returned array and calls a call back function 
    // on each array element (key), using ES6 arrow function (=>)
    // Or you can just use a normal function ((key) { blah blah }).
    Object.keys(obj).forEach(key => {

        // The bellow line prints out all keys with their 
        // respective value in obj.
        // key comes from the returned array in Object.keys(obj)
        // obj[key] returns the value of key in obj
        console.log("\n" + key + ": " + obj[key]);
    });
}

嗨,您能否添加有关您的答案的更多信息,仅提供代码无济于事。
嗨@Nicolas,我在代码中添加了逐行解释。如果还不清楚,请告诉我
因为forEach skips empty values,我认为您可以摆脱 if 并像 Frank Roth 的回答那样做 Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));
J
JSON C11

如果您的环境支持 ES2017,那么我会推荐 Object.entries:

Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`);
});

Mozillas Object.entries() 文档所示:

Object.entries() 方法返回给定对象自己的可枚举属性 [key, value] 对的数组,其顺序与 for...in 循环提供的顺序相同(不同之处在于 for-in 循环枚举原型链中的属性)。

基本上使用 Object.entries,我们可以放弃旧的 for...in 循环所需的以下额外步骤:

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}

C
Cyril N.

Dominik's 答案是完美的,我只是更喜欢这样做,因为它更易于阅读:

for (var property in obj) {
    if (!obj.hasOwnProperty(property)) continue;

    // Do stuff...
}

应该是 Object 和大写的 o,不是吗?
@Jonathan 注意它是第一行中的 object 变量。
我已经更新了代码以避免混淆;)
R
Rob Sedgwick

jquery 允许你现在这样做:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});

$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)}) $.each 是对象的 not suitable。如果一个对象恰好有一个长度属性并且它的值恰好为零,则整个对象被视为一个空数组。
Details 为什么我认为这是一种招致错误的方法
V
Vappor Washmade

for...in 循环表示对象中的每个属性,因为它就像一个 for 循环。您通过执行以下操作在 for...in 循环中定义了 propt:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

for...in 循环遍历对象的可枚举属性。无论您定义或放入 for...in 循环中的哪个变量,每次转到它迭代的下一个属性时都会发生变化。 for...in 循环中的变量遍历键,但它的值是键的值。例如:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

您可以看到变量与变量的值有何不同。相反,for...of 循环则相反。

我希望这有帮助。


d
dylanh724

上面的答案有点烦人,因为在确保它是一个对象之后,它们没有解释你在 for 循环中做了什么:你不直接访问它!您实际上只收到了您需要应用到 OBJ 的 KEY:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

这都是 ECMA5 安全的。甚至可以在像 Rhino 这样的蹩脚 JS 版本中工作;)


shouldBeBar 对于所有三个迭代都是未定义的。
undefined 是不可能的,因为它已经在您面前明确定义了 :) 这会导致两种可能性:(1) 您是否在 if() 块的外部检查 shouldBeBar?那么是的,它将是未定义的(超出范围)。或者(2)您是否输入了 var 名称?
D
Dimitar Nikovski

添加 ES2015 对 Reflect.ownKeys(obj) 的使用,并通过迭代器迭代属性。

例如:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

可以通过以下方式迭代

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

如果您想直接迭代对象的键值,您可以定义一个 iterator,就像 JavaScipts 的字符串、数组、类型化数组、Map 和 Set 的默认迭代器一样。

JS 将尝试通过默认的迭代器属性进行迭代,该属性必须定义为 Symbol.iterator

如果您希望能够遍历所有对象,可以将其添加为 Object 的原型:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

这将使您能够使用 for...of 循环迭代对象的值,例如:

for(val of obj) { console.log('Value is:' + val ) }

注意:截至撰写此答案时(2018 年 6 月),除 IE 之外的所有其他浏览器都支持生成器和通过 Symbol.iterator 进行的 for...of 迭代


尽管您实际上并没有回答 OP 的问题,但这对我很有帮助,我还不知道 Reflect。
P
Philll_t
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).forEach((item) => {console.log("item", obj[item])})

// a
// 3
// 2

正如其他评论中提到的,forEach 在这里更合适,因为 map 旨在返回一个新数组,其中包含在每次迭代中调用代码块的结果。但是我们只对每次迭代的副作用感兴趣,而不是返回值,因此我们不需要 map 给我们的那个新数组。
S
Sunny

您可以使用 for...inforEach 循环访问对象的嵌套属性。

对于...在:

for (const key in info) {
    console.log(info[key]);
}

对于每个:

Object.keys(info).forEach(function(prop) {
    console.log(info[prop]);
    // cities: Array[3], continent: "North America", images: Array[3], name: "Canada"
    // "prop" is the property name
    // "data[prop]" is the property value
});

P
Paul Rooney

您可以使用 Lodash。 The documentation

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});

为什么这个“答案”有10个赞成票?它完全无法回答这个问题。我开始对普通 JS 开发人员的智慧失去信心。
@developerbmw 我知道使用 ES6 功能是更正确的方法,但我在一年前就已经回答过了。请在您有时间的时候与我们分享您的想法。
这个想法是更多地关注本地方法,而不是建议用户在他们的页面中添加一个 10000 行的库。不要误会我的意思,我确实喜欢使用 Lodash,但它是有时间和地点的,但不是这个。
@user9016207 这个答案来自 2016 年,当时更适用 - 特别是如果你已经在使用 lodash。现在,如果您需要来自 lodash 的单个 fns,您可以一次获得一个,例如 npmjs.com/package/lodash.keys
F
Fellow Stranger
Object.keys(obj).forEach(key =>
  console.log(`key=${key} value=${obj[key]}`)
);

R
Redu

如今,您只需添加 Symbol.iterator 方法即可将标准 JS 对象转换为可迭代对象。然后,您可以使用 for of 循环并直接访问其值,甚至可以在对象上使用扩展运算符。凉爽的。让我们看看我们是如何做到的:

var o = {a:1,b:2,c:3}, a = []; o[Symbol.iterator] = function*(){ var ok = Object.keys(this);我 = 0; while (i < ok.length) 产生 this[ok[i++]]; }; for (var value of o) console.log(value); // 或者你甚至可以这样做 a = [...o];控制台.log(a);


有趣的方式来做到这一点。感谢function*的发现!
不错,你甚至可以使用方法,如果属性也是对象!
a
arb

您的 for 循环正在遍历对象 obj 的所有属性。 propt 在 for 循环的第一行中定义。它是一个字符串,是 obj 对象的属性名称。在循环的第一次迭代中,propt 将是“名称”。


佚名

JavaScript 中的对象是属性的集合,因此可以在 for each 语句中循环。

您应该将 obj 视为键值集合。


!重要的区别是这些“属性列表”可以将名称作为键,而普通的 JS 数组只能将数字作为键。
J
Justin

如果运行 Node,我建议:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});

i
iRohitBhatia

虽然评价最高的答案是正确的,但这里有一个替代用例,即如果您正在迭代一个对象并希望最终创建一个数组。使用 .map 而不是 forEach

const newObj = Object.keys(obj).map(el => {
    //ell will hold keys 
   // Getting the value of the keys should be as simple as obj[el]
})

R
Raman Sohi

for..in 循环的作用是创建一个新变量(var someVariable),然后将给定对象的每个属性一一存储在这个新变量(someVariable)中。因此,如果您使用块 {},您可以迭代。考虑以下示例。

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet

鉴于它的简单性,对此表示赞同。在我的用例中,我需要检查对象中的所有属性是否存在可疑值 - NaN、null、未定义(它们是图形上的点,这些值阻止图形绘制)。要获取值而不是名称,您只需在循环中执行 obj[someVariable]。也许它被如此低估的原因是因为它不是递归的。因此,如果您有一个高度结构化的对象,这将不是一个适当的解决方案。
@KatharineOsborne 或者可能是因为以下短语有点神秘:“因此,如果你使用块 {},你可以迭代。”代码比文本说的更多。
J
Jadiel de Armas

我想补充上面的答案,因为您可能与 Javascript 有不同的意图。 JSON 对象和 Javascript 对象是不同的东西,您可能想使用上面提出的解决方案遍历 JSON 对象的属性,然后感到惊讶。

假设您有一个 JSON 对象,例如:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

迭代其“属性”的错误方法:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

在遍历 prop1prop2 以及 prop3_1 的属性时,您可能会惊讶地看到控制台记录 01 等。这些对象是序列,序列的索引是 Javascript 中该对象的属性。

递归遍历 JSON 对象属性的更好方法是首先检查该对象是否为序列:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}

O
Ondrej Svejdar

还添加了递归方式:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

用法:

iterate({ foo: "foo", bar: { foo: "foo"} }); 

@faiz - 请参阅我的评论,当您反复穿过具有循环引用的对象时,它可以防止陷入无限循环
F
Faiz Mohamed Haneef

在这里,我迭代每个节点并创建有意义的节点名称。如果您注意到,instanceOf Array 和 instanceOf Object 几乎做同样的事情(在我的应用程序中,我给出了不同的逻辑)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

注意 - 我受到 Ondrej Svejdar 的回答的启发。但是这个解决方案有更好的性能和更少的歧义


H
HovyTech

您基本上想要遍历对象中的每个属性。

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

K
Konrad Kiss

为了进一步完善已接受的答案,值得注意的是,如果您使用 var object = Object.create(null) 实例化对象,则 object.hasOwnProperty(property) 将触发 TypeError。所以为了安全起见,你需要像这样从原型中调用它:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}

K
Kamil Kiełczewski

检查类型

您可以通过以下方式检查 propt 如何表示对象属性

typeof propt

发现它只是一个字符串(属性名称)。由于 for-in js“内置”循环的工作方式,它提出了对象中的每个属性。

var obj = { name: "Simon", age: "20", Clothing: { style: "simple", hipster: false } } for(var propt in obj){ console.log(typeof propt, propt + ': ' + 对象 [属性]); }


d
danday74

如果您只想迭代以映射属性值,那么 lodash 有 _.mapValues

const obj = { a: 2, b: 3 } const res = _.mapValues(obj, v => v * 2) console.log(res)