Open sisterAn opened 3 years ago
function(index, dele) { if(index === undefined || (dele === undefined && typeof dele === 'number')) return '请输入正确完整条件' const arrLeft = [] const arrRight = [] const arrAdd = [] const deleArr = [] for(let i = 0; this.length > i; i++) { if(i < index) { arrLeft.push(this[i]) } else if(i >= index + dele) { arrRight.push(this[i]) } else { deleArr.push(this[i]) } } for(let i = 2; arguments.length > i; i++) { arrAdd.push(arguments[i]) } [...arrLeft, ...arrAdd, ...arrRight].forEach((item, index) => { this[index] = item }) return deleArr }
1、大佬这里的 over 需要 over > 0
吧?
let over = addCount - delCount;
if(over) {
// 向后移
2、这块的逻辑处理好像不太对(稀疏数组也存在类似情况)。
} else if (over < 0) {
// 向前移
for(let i = startIndex + delCount; i <= array.length - 1; i++) {
if(i + Math.abs(over) > array.length - 1) {
// 删除冗于元素
delete array[i]
continue
}
array[i] = array[i + Math.abs(over)]
}
}
}
例如:
var arr = [1,2,3,4,5];
arr.splice(0, 3, 6, 7);
console.log(arr); //
- 预期结果:[6, 7, 4, 5]
- 实际结果:[6, 7, 3, 5]
移动元素函数里 判断over<0的情况 i应该从startIdx+delCount+over开始
/**
数组splice方法实现
arr.splice(startIdx,delCount,add1,add2,...);
*/
Array.prototype._splice = function () {
//1. 记录入参个数
let argumentsLen = arguments.length;
let start = arguments[0], deleteCount = arguments[1];
//2. 数组长度
let arrayLength = this.length;
let arr = Object(this);
//3. 添加元素个数
let addCount = argumentsLen > 2 ? argumentsLen - 2 : 0
console.log('addCount: ', addCount);
//4. 计算有效的开始位置start
let startIdx = computeSpliceStartIdx(start, arrayLength);
//5. 计算有效的删除个数
let delCount = computeSpiceDelCount(startIdx, deleteCount, arrayLength);
console.log('delCount: ', delCount);
//6. 记录删除的元素
let delElements = new Array(delCount);
recordDelElements(startIdx, delCount, arr, delElements);
//7. 判断是否是密封对象
if (delCount !== addCount && Object.isSealed(arr)) {
throw new TypeError('the arr is sealed')
}
//8. 判断是否是冻结对象
if (delCount > 0 && addCount > 0 && Object.isFrozen(arr)) {
throw new TypeError('the arr is frozen')
}
//移动数组元素
moveElements(startIdx, delCount, arr, addCount);
let i = startIdx;
let argumentsIdx = 2;
//插入新的元素
while (argumentsIdx < argumentsLen) {
arr[i++] = arguments[argumentsIdx++];
}
arr.length = arrayLength - delCount + addCount;
return delElements;
}
function computeSpliceStartIdx(start, arrayLength) {
if (start < 0) {
start += arrayLength;
return start < 0 ? 0 : start;
}
//start>0的情况
return start > arrayLength - 1 ? arrayLength - 1 : start;
}
//计算delCount
function computeSpiceDelCount(startIdx, deleteCount, arrayLength) {
if (deleteCount > arrayLength - startIdx) {
deleteCount = arrayLength - startIdx
}
if (deleteCount < 0) deleteCount = 0
return deleteCount;
}
//记录删除的元素
function recordDelElements(startIdx,delCount,arr,delElements) {
for(let i=0;i<delCount;i++) {
delElements[i] = arr[startIdx+i];
}
}
//移动数组
function moveElements(startIdx, delCount, arr, addCount){
let over = addCount - delCount;
console.log('over: ', over);
if(over>0) {
//增加的数大于了删除的数 向后移动
for(let i=arr.length-1;i>=startIdx+delCount;i--) {
arr[i+over] = arr[i];
}
} else if(over<0) {
//增加的数小于删除的数 向前移动
for(let i=startIdx+delCount+over;i<=arr.length-1;i++) {
if(i+Math.abs(over)>arr.length-1) {
delete arr[i]
continue
}
arr[i] = arr[i+Math.abs(over)];
}
console.log('arr: over<0', arr);
}
}
let arr = [1, 2, 3, 4, 5];
arr._splice(1,3,6,7)
console.log('arr: ', arr);//arr: [ 1, 6, 7, 5 ]
Array.prototype.splice_ = function(start,deletecount,...args){
let result = []
if(deletecount===undefined){
for(let i = start;i<this.length;i++){
result.push(this[i])
}
let k = 0,j =start;
let finalLen = this.length-result.length+args.length
if(args.length){
while(k<args.length){
this[j] = args[k]
k++
j++
}
while(this.length>finalLen){
this.pop()
}
}
}else if(deletecount<=0){
if(args.length){
let tempList = []
for(let i = start;i<this.length;i++){
tempList.push(this[i])
}
let k = 0,j = args.length
while(k<tempList.length){
args[j] = tempList[k]
k++
j++
}
let m = 0,n =start;
while(m<args.length){
this[n] = args[m]
m++
n++
}
}
}else if(deletecount>0){
for(let i = start;i<start+deletecount;i++){
result.push(this[i])
}
if(args.length){
let tempList = []
for(let i = start+deletecount;i<this.length;i++){
tempList.push(this[i])
}
let k = 0,j = args.length
while(k<tempList.length){
args[j] = tempList[k]
k++
j++
}
let m = 0,n =start;
let finalLen = this.length-result.length+args.length
while(m<args.length){
this[n] = args[m]
m++
n++
}
while(this.length>finalLen){
this.pop()
}
}
}
return result
}
let arr= [1,2,3,4]
arr.splice_(2,2,'111')
console.log(arr)
splice
Array.prototype.splice() 的用法如下:
array.splice(start)
:删除数组中从下标start
开始(包含start
)的所有元素array.splice(start, deleteCount)
:删除数组中从下标start
开始(包含start
)的deleteCount
元素array.splice(start, deleteCount, item1, item2, ...)
:删除数组中从下标start
开始(包含start
)的deleteCount
元素,然后在相同位置上插入item1, item2, ...
特征包括如下:
start
:可正可负,正数表示从下标为start
的位置开始修改,如果start > array.length - 1
,则表示从数组末尾处开始修改;负数表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n
)deleteCount
:表示从start
开始要移除的元素个数,省略则表示把start
之后的所有元素都移除,如果是0
或负数,则不移除元素item1, item2, ...
:要添加进数组的元素,从start
位置开始。如果不指定,则splice()
将只删除数组元素实现思路:
处理
start
负数或超出边界问题,计算真实有效的开始位置startIndex
处理
deleteCount
负数问题,计算真实有效的删除元素个数delCount
从
startIndex
开始删除delCount
个元素并原地添加item1, item2, …
(添加元素个数为addCount
)delCount
到新数组deletedElements
,用于array.splice
函数返回delCount > addCount
(删除的元素个数大于添加元素):将数组中startIndex + delCount
后的元素向前移动delCount - addCount
个位置,将添加元素拷贝进来delCount = addCount
(删除的元素个数等于添加元素):直接将添加元素覆盖删除元素即可delCount < addCount
(删除的元素个数小于添加元素):将数组中startIndex + delCount
后的元素向后移动addCount - delCount
个位置,将元素拷贝进来返回
deletedElements
代码实现:
补充:密封对象与冻结对象
V8源码
Array.prototype.splice源码地址
总结
splice
实现原理很简单,核心就是移动删除元素的边界,使无效元素个数与添加元素个数一致,然后用添加元素覆盖进去, 注意splice
是原地操作,不创建新数组,需要判读数组是否被密封或冻结完整代码实现