-
Notifications
You must be signed in to change notification settings - Fork 633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
字节:模拟实现 Array.prototype.splice #138
Comments
function(index, dele) { |
1、大佬这里的 over 需要
2、这块的逻辑处理好像不太对(稀疏数组也存在类似情况)。
例如: 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
是原地操作,不创建新数组,需要判读数组是否被密封或冻结完整代码实现
The text was updated successfully, but these errors were encountered: