导航菜单
  • 首页
  • 首页>前端万博manbext备用网址>JavaScript万博manbext备用网址

    用原型重写数组基础方法(上)

    通过用原型的方式重写数组的方法,加深对数组和原型的掌握。

    先从最简单的开始:

    1、push

            //  push(val1,val2,...)
            // 1、数组的方法,只能数组对象调用
            // 2、功能是在数组的尾部添加数据
            // 3、可以添加多个数据,逗号隔开
            // 4、返回的是数组的length值,是数字类型
            // 5、改变了原始数组
            Array.prototype.myPush = function () {
                const arr = this;
                // 保存长度,减少对数组长度的反复查找,节约性能
                let len = arr.length;
                for (let i = 0; i < arguments.length; i++) {
                    arr[len++] = arguments[i];
                }
                return len;
            }

    2、pop

            // pop()
            // 1、功能是:删除数组尾部的一个值
            // 2、返回被删除的数据
            // 3、改变的是原数组
            Array.prototype.myPop = function () {
                const arr = this;
                let len = arr.length;
                // 必须要判断数组的长度,如果为0,直接返回undefined
                if (len == 0) return;
                let lastItem = arr[len - 1];
                // 数组的长度少一个1,就会直接删除最后一个值。
                arr.length--;
                return lastItem;
            }

    3、unshift

            // unshift(val,val,...) 
            // shift()
            // 在数组的头部添加数据和删除数据,是先后先出的模式。
            Array.prototype.myUnshift = function () {
                const arr = this;
                let len = arr.length;
                let argL = arguments.length;
                // 加入参数长度为0,返回数组的长度,不用操作后面
                if (argL == 0) return len;
                // 先把原始数组的值往右移动参数的个数
                for (let i = 0; i < len; i++) {
                    arr[argL + i] = arr[i];
                }
                // 再把参数的值一一对应到数组中
                for (let i = 0; i < argL; i++) {
                    arr[i] = arguments[i];
                    len++;
                }
                return len;
            }

    4、shift

            // shift
            Array.prototype.myShift = function () {
                const arr = this;
                let len = arr.length;
                //如果数组长度为0,则不执行,返回undefined。
                if (len == 0) return;
                //  取出第一个值
                let firstItem = arr[0];
                //  遍历后面所有值,往前移动一个位置。
                for (let i = 1; i < len; i++) {
                    arr[i - 1] = arr[i];
                }
                //  数组长度减1
                arr.length--;
                //  返回第一个值
                return firstItem;
            }

    5、join

            // join(分隔符)
            // 功能是:把数组的值转成字符串,用分隔符拼接。
            // 参数是可以缺省,默认是逗号隔开。
            // 如果是空字符串,直接把数组拼接成字符串
            // 返回的是字符串
            Array.prototype.myJoin = function (sep) {
                const arr = this;
                if (sep || sep === '') {
                    sep = sep;
                } else {
                    sep = ',';
                }
                let len = arr.length;
                let str = '';
                if (len == 0) return str;
                for (let i = 0; i < len; i++) {
                    if (i < len - 1) {
                        str += arr[i] + sep;
                    } else {
                        str += arr[i];
                    }
                }
                return str;
            }

    6、concat

            // concat(val,val,...)
            // 功能是:把多个值合并在新数组中返回
            // 参数:任意数据类型的值
            // 返回值:一个新数组
            // 不改变原数组,返回新数组,但是是浅拷贝
            // 能够拆开第一层数组。
            Array.prototype.myConcat = function () {
                const arr = this;
                let len = arr.length;
                let argsL = arguments.length;
                let newArr = [];
                // 先把原数组遍历出来,把值赋值给新数组
                for (let i = 0; i < len; i++) {
                    newArr[i] = arr[i];
                }
                // 如果参数长度为0,返回新数组。
                if (argsL == 0) return newArr;
    
                // 遍历参数
                for (let i = 0; i < argsL; i++) {
                    // 如果参数中有数组,则解开第一层数组的值
                    if (arguments[i] instanceof Array) {
                        for (let j = 0; j < arguments[i].length; j++) {
                            newArr[len++] = arguments[i][j];
                        }
                    } else {
                        newArr[len++] = arguments[i];
                    }
                }
                return newArr;
            }

    7、slice

            // slice(start,end)
            // 功能:截取数组的一段值
            // 参数:start表示开始的索引值,end表示结束的索引值,不包括结束的索引值。[start,end),可以为负值。
            // 返回值:返回一个截取出来的新数组
            // 参数缺省,表示把所有的值都截取出来,返回到一个新数组,可以用来对数组进行浅拷贝。
            // 没有修改原数组
            // slice
            Array.prototype.mySlice = function (start, end) {
                const arr = this;
                let len = arr.length;
                let argsL = arguments.length;
                let newArr = [];
                // 如果数值长度为0,返回新的空数组
                if (len == 0) return newArr;
                // 如果第一个参数缺省,默认值为0
                start = arguments[0] || 0;
                // 如果第二个参数缺省,默认值为数组的长度
                end = arguments[1] || len;
    
                // 如果第一个参数小于0
                if (arguments[0] < 0) {
                    start = len + arguments[0];
                }
                // 如果第二个参数小于0
                if (arguments[1] < 0) {
                    end = len + arguments[1];
                }
                // 如果第一个参数大于等于第二个参数,返回新的空数组
                if (start >= end) return newArr;
                // 遍历start到end之间的值
                for (let i = start; i < end; i++) {
                    newArr.push(arr[i]);
                }
                return newArr;
            }

    8、splice

            // splice(index,howmany,val,val,....)
            // 功能:对数组任意位置进行增加,删除,修改值
            // 修改原数组,返回被删除的值构成的新数组,如果没有删除值,返回空数组。
            // 可以添加或者替换数组的一部分
            Array.prototype.mySplice = function () {
                const arr = this;
                let len = arr.length;
                let argsL = arguments.length;
                let newArr = [];
                // 如果没有参数,返回空数组
                if (argsL == 0) return newArr;
                // 第一个参数作为起始位置
                let start = arguments[0];
                // 如果第一个参数小于0
                if (start < 0) {
                    start = start + len;
                }
                // 如果第一个参数不是数字,或者是NaN,默认0
                if (typeof start !== 'number' || start !== start || start < 0) {
                    start = 0;
                }
                // 如果第一个参数大于数组的最大下标值
                if (start > len - 1) {
                    start = len;
                }
                // 第二个参数作为删除的个数。
                // let howmany = (arguments[1] !== undefined) ? arguments[1] : len - start;
                let howmany = arguments[1];
                // 如果没有传参第二个参数,默认为删除起始位置后面的所有值。如果为0,不删除。
                // 这里不要用短路||运算符,否则参数为0的时候,也会返回后面len - start的值。
                if (arguments[1] === undefined) {
                    howmany = len - start;
                }
    
                // 如果第二个参数不是数字或者是NaN,默认为0
                if (typeof howmany !== 'number' || howmany !== howmany) {
                    howmany = 0;
                }
                // 如果被删除的个数大于了可以删除的个数,则只能截取到末尾。
                if (howmany > len - start) {
                    howmany = len - start;
                }
                // 把要删除的值添加到新数组中
                for (let i = start; i < start + howmany; i++) {
                    newArr.push(arr[i]);
                }
                // 获取第三个以后的参数
                let addArgs = Array.prototype.slice.call(arguments, 2);
                // 要添加的参数的长度
                let addArgsL = addArgs.length;
    
                // 如果有参数,则根据howmany来看,是添加还是替换。
                // 如果是插入或替换,只需用替换元素长度减去删除的个数即可得出向后移动的位置数,把插入替换的元素在移动出空缺的位置上对号入座;
    
                if (addArgsL > 0) {
                    // 添加的个数和删除的个数的差值
                    let num = addArgsL - howmany;
                    // 如果添加的个数大于删除的个数,则是从后面扩展数组。
                    if (num > 0) {
                        // 必须是从后面往前面遍历,否则前面的数会把后面的数覆盖
                        for (let i = len - 1; i >= start; i--) {
                            arr[i + num] = arr[i];
                        }
                    } else {
                        // 如果添加的个数少于要删除的个数,则从起始位置加上删除个数的位置开始往前移动
                        for (let i = start + howmany; i < len; i++) {
                            arr[i + num] = arr[i];
                        }
                    }
    
                    // 改变数组的长度,如果添加的参数少于删除的个数,数组要把后面多余的数删除。
                    // 数组原始的长度加上添加和删除的差值
                    arr.length = len + num;
                    console.log(addArgsL, howmany, arr.length, start);
                    // 再把要添加的数对应到相应的位置上。
                    for (let j = 0; j < addArgsL; j++) {
                        arr[start++] = addArgs[j]
                    }
                } else {
                    // 没有要添加的参数,值直接删除。
                    for (let i = start; i < len; i++) {
                        arr[i] = arr[i + howmany];
                    }
                    arr.length = arr.length - howmany;
                }
                return newArr;
            }

    9、reverse

            // reverse()
            // 功能:翻转数组的值
            // 没有参数
            // 返回原数组
            Array.prototype.myReverse = function () {
                const arr = this;
                let len = arr.length;
                if (len == 0) return arr;
                let centerpos = Math.floor(len / 2);
                let temp = '';
                for (let i = 0; i < centerpos; i++) {
                    temp = arr[i];
                    arr[i] = arr[len - 1 - i];
                    arr[len - 1 - i] = temp;
                }
                return arr;
            }

    10、sort

            // sort
            // v8的sort源代码使用的是数组小于10,插入排序,大于10,快速排序,大于1000,插入和快排混合。
            // https://zhuanlan.zhihu.com/p/33626637
            // https://zhuanlan.zhihu.com/p/24050357
            // 这里使用的是冒泡排序
            Array.prototype.mySort = function () {
                const arr = this;
                // 如果没有传参数
                // 默认字符串排序
                if (!arguments[0]) {
                    for (let i = 0; i < arr.length - 1; i++) {
                        for (let j = 0; j < arr.length - 1 - i; j++) {
                            // 如果是默认排序,则转成字符串,升序排列
                            if (String(arr[j]) > String(arr[j + 1])) {
                                let temp = arr[j + 1];
                                arr[j + 1] = arr[j];
                                arr[j] = temp;
                            }
                        }
                    }
                    return arr;
                }
                else {
                    let fn = arguments[0];
                    for (let i = 0; i < arr.length - 1; i++) {
                        for (let j = 0; j < arr.length - 1 - i; j++) {
                            // 调用比较函数,计算相邻两个数的差值
                            let result = fn(arr[j], arr[j + 1]);
                            // 如果差值大于0,则交换两个数的位置
                            if (result > 0) {
                                let temp = arr[j + 1];
                                arr[j + 1] = arr[j];
                                arr[j] = temp;
                            }
                        }
                    }
                    return arr;
                }
            }

    11、indexOf

            // indexOf(item,start)
            // 功能:查找数组里面是否有item这个项.可以指定从哪个索引位置开始查找,start缺省,表示0
            // 返回值:如果找到了,返回这个item项的索引值,没找到,返回-1
            // 这个方法不能判断数组里面是否有NaN,因为NaN === NaN,返回false
            Array.prototype.myIndexOf = function (ele, start) {
                const arr = this;
                if (arr.length == 0) return -1;
                start = start || 0;
                let result = -1;
                for (let i = start; i < arr.length; i++) {
                    // 如果元素相等,返回第一个相等的元素的下标值
                    if (ele === arr[i]) {
                        result = i;
                        break;
                    }
                }
                return result;
    
            }

    12、lastIndexOf

            // lastIndexOf(item,start)
            // 功能和indexOf()类似,只不过是从数组的右边往左边查找
            // 数组的元素的索引值是不变的,只是从右边往左边查找,返回的依然是值固定的索引值.
            Array.prototype.myLastIndexOf = function (ele, start) {
                const arr = this;
                let len = arr.length;
                if (len == 0) return -1;
                start = start || len - 1;
                let result = -1;
                for (let i = start; i >= 0; i--) {
                    // 如果元素相等,返回第一个相等的元素的下标值
                    if (ele === arr[i]) {
                        result = i;
                        break;
                    }
                }
                return result;
    
            }

    写了好久终于把常规的数组方法写完了,还有后面迭代的方法没有……

    点赞


    1
    保存到:

    相关文章

    发表评论:

    ◎请发表你卖萌撒娇或一针见血的评论,严禁小广告。

    Top