Array.prototype.copyWithin
代码均来自:MDN
原数组将被改变,但是数组的长度不会发生变化,IE系列不支持此方法
if (!Array.prototype.copyWithin) {
Array.prototype.copyWithin = function(target, start/*, end*/) {
// Steps 1-2.
//过滤null和undefined eg: Array.prototype.copyWithin.call(null)
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
// >>> 0 的作用(无符号右移):
// 1.能转换为数值的先转换为数值然后在右移
// 2.非数值类型不能转换为数值的返回0
// 3.自然数向左取整,负数会转换为正数
var len = O.length >>> 0;
// Steps 6-8.
// >> 0 的作用(有符号右移):
// 1.能转换为数值的先转换为数值然后在右移
// 2.非数值类型不能转换为数值的返回0
// 3.自然数向左取整,负数向右取整
var relativeTarget = target >> 0;
//扶正target索引,负数绝对值超过len取0,正数超过len取len
var to = relativeTarget < 0 ?
Math.max(len + relativeTarget, 0) :
Math.min(relativeTarget, len);
// Steps 9-11.
var relativeStart = start >> 0;
var from = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 12-14.如果没传end取len,传了end就按照上面的规则扶正end
var end = arguments[2];
var relativeEnd = end === undefined ? len : end >> 0;
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 15.
var count = Math.min(final - from, len - to);
// Steps 16-17.
var direction = 1;
//from to final count最大为len最小为0
//from复制的开始索引, to赋值的开始索引, final复制的结束索引,count
/**
* a. from === to
* 1. from === final count = 0; return o;
* 2. from < final count = final - from; 正常循环,return o;
* 3. from > final count < 0; return o;
* b. from > to
* 1. from === final count = 0; return o;
* 2. from < final count = final - from; 正常循环,return o;
* 3. from > final count < 0; return o;
* c. from < to
* 1. from === final count = 0; return o;
* 2. from < final
* i. 如果 final - from <= len - to, count = final - from,
* ii. 如果 final - from > len - to, count = len - to,
* 按i和ii这种分析方法,不适合恰当,可以画图来示意,就是to始终落在from和final的区间里,
* 这种情况就需要特殊处理也就是下面的 from < to && to < (from + count)
* 3. from > final count < 0; return o;
*/
if (from < to && to < (from + count)) {
direction = -1;
from += count - 1;
to += count - 1;
}
// Step 18.
while (count > 0) {
if (from in O) {
//这里说明copyWhthin的拷贝是浅拷贝,如果更改了arr里的非原子类型的值,很可能引起多处被修改的问题
O[to] = O[from];
} else {
delete O[to];
}
from += direction;
to += direction;
count--;
}
// Step 19.
return O;
};
}
- copyWithin 函数是设计为通用的,其不要求其 this 值必须是一个数组对象
var obj = {length: 2, a: 1, 1: 2};
Array.prototype.copyWithin.call(obj, 0, "a")
//{1: 2, length: 2, a: 1}
Array.prototype.copyWithin.call({length: 5, a:1, b:2, c:3, d:4, e:5, 1: 1, 2: 2}, 0, "c")
//{1: 1, 2: 2, length: 5, a: 1, b: 2, c: 3, d: 4, e: 5}