为Javascript原型定义函数时,为什么函数名称出现在for循环中?

时间:2017-10-04 00:39:56

标签: javascript arrays

我相对较新的Javascript及其无限的伟大。我想练习为对象原型定义自己的函数,所以我练习为contains()编写Array函数:

if (!Array.prototype.contains){
    Array.prototype.contains = function(target){
        for (var i in this){
            console.log(i);
            if (this[i] == target) return true;
        }
        return false;
    }
}

基本上,contains()遍历this内的每个元素以查找target。但是,我注意到console.log(i)会返回索引号(即012等),具体取决于元素的数量在数组内部。但是,它也总是打印出contains!这是我的console.log的输出,只有一个元素在数组中:

0
contains

但是,如果我改变迭代for循环的方式,我就不会得到contains输出:

if (!Array.prototype.contains){
    Array.prototype.contains = function(target){
        for (var i = 0; i < this.length; i++){
            console.log(i);
            if (this[i] == target) return true;
        }
        return false;
    }
}

输出:

0

现在我已经通读了这个StackOverflow post来解释使用for... in进行数组迭代的危险,但我不知道以编程方式解释为什么contains是出现在我的第一个代码段中。如果我在Firefox开发人员控制台上console.log(this),我会按预期收到一个Array对象:

Array [ "scrubBackButton2", "scrubNextButton1" ]

数组对象的最后一个元素是否始终是使用?

调用的函数的名称

我主要是通过反复试验来学习JS,所以如果我错过了一个好的答案,请务必将我推荐给好的文档或之前的帖子!

1 个答案:

答案 0 :(得分:2)

for ... in循环将遍历对象的每个可枚举属性。因此它将遍历['1']属性和['2']属性等。数组所具有的属性中有一个名为['contains']的函数。为什么会这样?因为你把它放在那里! :)

或者更确切地说,你把它放在它的原型上。但就for ... in而言,这几乎是一样的。它将循环遍历对象上的所有可枚举属性,以及它从其原型继承的可枚举属性,以及其原型的原型等。在Array.prototype上有很多属性,但它们不是可枚举的(这是为什么它还没有退出'推','pop','map'等)。你放在那里的那个是可枚举的,因为这是属性的默认属性。

正如您所指出的,for ... in不适合遍历数组,因此我建议您更改代码以执行其他操作。可以是循环手册,例如this.forEachfor ... of

这一行下面还有其他一些选项,但是他们会用你很少写的代码进入杂草(但是再一次,修改Array.prototype是你很少会做的事情)。

======

如果你想保留for ... in循环,一个选项是明确检查以确保你正在查看的每个属性来自对象本身,而不是来自其原型。为此,您可以使用hasOwnProperty。如果属性来自原型,hasOwnProperty将返回false。如果属性属于此特定对象,则返回true;

if (!Array.prototype.contains){
    Array.prototype.contains = function(target){
        for (var i in this){
            if (!this.hasOwnProperty(i)) continue;
            console.log(i);
            if (this[i] == target) return true;
        }
        return false;
    }
}

[1, 2].contains(5)

另一种可能性是使包含不可枚举。通过这样做,for ... in循环将跳过它(Object.keys())

也是如此

if (!Array.prototype.contains){
    function contains(target){
        for (var i in this){
            console.log(i);
            if (this[i] == target) return true;
        }
        return false;
    }

    Object.defineProperty(Array.prototype, 'contains', {
        enumerable: false,
        configurable: false,
        writeable: false,
        value: contains
    });
}

[1, 2].contains(5);

有关定义属性的更多信息,请参阅此页面:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty