请求解释数组去重代码逻辑及a[this[i]]的含义
嘿,我来帮你把这段数组去重的代码拆解得明明白白,尤其是你搞不懂的a[this[i]]部分,咱们一步一步来捋:
整体功能先搞懂
这段代码给JavaScript的Array原型添加了一个unique方法,任何数组调用arr.unique()后,就能移除里面的重复元素,而且是直接修改原数组并返回它。核心思路是利用对象的键不能重复这个特性来实现去重。
逐行拆解细节
1. 给数组原型加方法
Array.prototype.unique = function() {
这行代码的作用是:让所有数组实例都拥有unique这个方法——比如你有个数组let arr = [1,2,2,3],就能直接写arr.unique()来去重,不用每次都写一遍去重逻辑。
2. 创建临时存储对象
var a = {}; //new Object
这里创建了一个空对象a,它的核心作用是记录哪些数组元素已经出现过,相当于一个“查重字典”。
3. 遍历数组标记重复项
for (var i = 0; i < this.length; i++) { if (typeof a[this[i]] == 'undefined') { a[this[i]] = 1; } }
这里是代码的核心,重点解释你困惑的a[this[i]]:
- 首先,
this在这里指的是调用unique方法的那个数组本身(比如刚才的arr),this[i]就是当前循环到的数组元素(比如i=0时就是1,i=1时就是2)。 a[this[i]]其实就是访问对象a中,键为当前数组元素的属性。举个例子,如果当前元素是2,那就是a["2"](因为对象的键本质都是字符串,数字会被自动转成字符串)。
这个if判断的逻辑是:如果对象a里还没有以当前元素为键的属性(说明这个元素是第一次出现),就给a添加这个键,值设为1(值是什么无所谓,只要存在就行)。如果元素重复出现,a[this[i]]就已经存在,不会再执行赋值操作,这样就完成了重复项的标记。
4. 清空原数组
this.length = 0; //clear the array
把原数组的长度设为0,相当于直接清空了原数组——因为JavaScript数组的长度是动态的,设为0后所有元素都会被移除。
5. 把去重后的元素放回原数组
for (var i in a) { this[this.length] = i; }
遍历对象a的所有键(这些键就是刚才去重后的数组元素),把每个键添加回原数组。这里this.length每次添加元素后会自动递增,所以刚好能把元素依次放到数组的第0、1、2...个位置。
6. 返回修改后的数组
return this;
最后返回已经去重的原数组(注意:这个方法是直接修改原数组,不是返回一个新数组)。
小提醒:这段代码的局限性
不过要注意,这段代码有个小缺陷:
- 因为对象的键会被转成字符串,所以如果数组里同时有
1(数字)和"1"(字符串),会被当成重复项处理; - 对于引用类型(比如对象、数组),比如
[{name: 'a'}, {name: 'a'}],因为它们转成字符串都是"[object Object]",会被误判为重复项,无法正确去重。
内容的提问来源于stack exchange,提问作者JH YOO

