for..in and hasOwnProperty

83

可能是重复的问题:
如何在JavaScript中检查对象是否具有特定属性?

我在 Twitter 的 JavaScript 文件中找到了以下片段。为什么他们需要调用 hasOwnProperty 函数来查看 dict 是否具有 key 属性呢?for 循环正在针对 'dict' 中的每个 'key' 运行,这意味着 'dict' 具有 'key'。难道我错过了什么吗?

function forEach(dict, f) {
    for (key in dict) {
        if (dict.hasOwnProperty(key))
            f(key, dict[key]);
    }
}

3
这里解释得很清楚:https://dev59.com/_HVC5IYBdhLWcg3w9GHM#136411 - kevingessner
好像 key 是全局的,这段代码是从哪里来的?你能贴一个链接吗? - elclanrs
@elclanrs 我错了,这段代码来自Chrome的utils.js文件。 - scusyxx
1
@elclanrs 更有可能的是他不知道他的代码正在创建这个全局变量,很容易在for in循环中忘记使用var编辑:哦,我刚刚读到这不是他的代码...有趣。 - ajax333221
他肯定是写了这段代码然后忘记了。谷歌代码不可能会漏掉括号并且忘记 var 这个关键字。 - elclanrs
显示剩余2条评论
4个回答

84
因为如果你不这样做,它会循环遍历原型链上的每个属性,包括那些您不知道的属性(可能是由于某人更改本机对象原型而添加的)。
这种方式只保证该对象实例上存在的键。

2
我就是不明白,一个如此流行且快速发展的语言,比如JS,在经过这么多年和标准化之后,仍然没有一个适当的循环来迭代对象,而你不必在每个循环步骤中调用hasOwnProperty() - Sceptical Jule
6
for..in 循环可以获取包括继承属性在内的可枚举属性。如果你只想获取自身的可枚举属性,可以使用 for (const key of Object.keys(obj))。有关属性的可枚举性和所有权的详细信息,请查看此表格 - adiga
1
@ScepticalJule,我对网络开发的总体问题感到怀疑。即使它变得如此流行,今天所有的网络技术都只是在烂30年技术的基础上不断地增加层次。我希望我们可以抛弃这一切,创造出真正强大、直观且适合当今需求的东西。 - Johan Wintgens

36
hasOwnProperty 方法可以判断一个属性是直接在对象实例中定义的,还是来自于对象原型链继承而来的。 考虑如下示例:
function ObjWithProto() {
    this.foo = 'foo_val';
}

ObjWithProto.prototype = {bar: 'bar_val'};

var dict = new ObjWithProto();
dict.foobar = 'foobar_val';

也就是说,您有一个具有属性foofoobar对象dict,它还从其原型链继承了属性bar

现在将其通过(修改过的)代码运行:

function forEach(dict) {
    var key;
    for (key in dict) {
        if (dict.hasOwnProperty(key)) 
            console.log('has', key, dict[key]);
        else 
            console.log('not', key, dict[key]);
    }
}
forEach(dict);

你会看到

has foo foo_val
has foobar foobar_val
not bar bar_val

这样可以将对象自身拥有的属性和继承的属性(通常是与循环无关的方法)分开。

此外,如果您现在执行dict.bar = 'new_bar_val';,则最后一个结果将更改为has bar new_bar_val,让您甚至可以区分与继承的同名属性。


5

在JavaScript中,每个对象都是一个字典。这意味着“toString”和其他每个方法都是每个对象的键:

var myObj = {};
console.log(myObj["toString"]);

但这个函数是从Object类继承来的,因此hasOwnProperty告诉您该键是否由字典拥有或者是否被继承。

"toString" in myObj; // true
myObj.hasOwnProperty("toString") // false

1

blockhead就在这里。例如,Prototype.js框架用于扩展本地数组以添加额外的辅助方法(我不知道框架当前版本的情况)。

因此,直接使用“for(key in dict)”将返回div的所有元素以及对辅助方法的引用。这有点出乎意料 :)


1
prototype.js 做了很多错误的事情。 - Joe Maffei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接