给数组原型对象添加方法

今天使用for...in方法的时候发现枚举到了意料之外的prototype内的方法,发现是没有正确为数组原型对象添加方法,在此记录。

问题

一般我们如何给一个数组原型对象添加方法呢,比如我们添加一个去重方法。

1
2
3
4
5
6
7
8
9
10
11
Array.prototype.unique = function () {
var n = {},
r = [];
for (var i = 0; i < this.length; i++) {
if (!n[this[i]]) {
n[this[i]] = true;
r.push(this[i]);
}
}
return r;
};

我看不少文章里这样就好了,这就会出现我刚刚说到的问题。在你使用for...in方法遍历数组时就会拿到unique这个 key 值,这个是不符合我们预期的。

其实出现这样的情况是因为Array.prototype对象的unique属性的描述值enumerabletrue,也就是可枚举,在枚举对象属性时会被枚举到(for...inObject.keys方法)。

根据MDN Web Docs说明,可枚举属性是指那些内部 可枚举 标志设置为 true 的属性,对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true,对于通过 Object.defineProperty 等定义的属性,该标识值默认为 false。可枚举的属性可以通过 for...in 循环进行遍历(除非该属性名是一个 Symbol)。

解决

正确的方法如下,忽略方法内容。

方法一

先添加方法,再通过 Object.defineProperty 设置为不可枚举。

1
2
3
4
Array.prototype.unique = function () {};
Object.defineProperty(Array.prototype, "unique", {
enumerable: false,
});

方法二

或者直接通过 Object.defineProperty 方法添加。此时enumerable默认为false,不用特别指定。

1
2
3
Object.defineProperty(Array.prototype, "unique", {
value: function () {},
});