你知道常用方法的底层原理么?手写js源码

84 阅读4分钟

一。 Array.prototype.indexOf()

array.indexOf(element, start = 0);

Array.prototype.myIndexOf = function(str,start){
    // console.log('Array环境',this)
    //负索引从数组末尾开始计数
    //如果传的start<0,那么查找位置就从length+start开始查找,start不能小于-length,小于就从0开始搜索;start不能大于length
    if( start>= this.length ) return -1;
 
    let index = start<0 && start > -this.length ?this.length+start :start || 0
    for(let i=index;i<this.length;i++){
         if(this[i] === str) {
           return  i;
         }
     }
     return -1
 }

 var arr = [1,2,3,4,5,1,2,3,4,5]
 console.log(arr.indexOf(433),arr.indexOf(3))//-1 2
 console.log(arr.indexOf(2,3),arr.indexOf(1,13),arr.indexOf(3,-13))//6  -1 2
 console.log([].indexOf(6),arr.indexOf(''),arr.indexOf(null))//-1 -1 -1
 //从-3开始相当于[3,4,5]从这里找是否有匹配的值没有返回-1,-8 相当于从[3,4,5,1,2,3,4,5]找配置的数据,但是index还是从[1,2,3,4,5,1,2,3,4,5]第一个来计算
 console.log(arr.indexOf(2,-3),arr.indexOf(2,-8))// -1 6  


 console.log(arr.myIndexOf(433),arr.myIndexOf(3))//-1 2
 console.log(arr.myIndexOf(2,3),arr.myIndexOf(1,13),arr.myIndexOf(3,-13))//6  -1 2
 console.log([].myIndexOf(6),arr.myIndexOf(''),arr.myIndexOf(null))//-1 -1 -1
 console.log(arr.myIndexOf(2,-3),arr.myIndexOf(2,-8))// -1 6 

二。 Array.prototype.includes

array.includes(element, start = 0);

Array.prototype.myIncludes = function(str,start){
         //负索引从数组末尾开始计数
       //如果传的start<0,那么查找位置就从length+start开始查找,start不能小于-length,小于就从0开始搜索;start不能大于length
        if( start>= this.length ) return -1;
    
        let index = start<0 && start > -this.length ?this.length+start :start || 0
        for(let i=index;i<this.length;i++){
            if(this[i] === str) {
              return  true;
            }
        }
        return false
    }

    var arr = [1,4,6,9,89,3]
    console.log(arr.includes(433),arr.includes(3))//false true
    console.log([].includes(6),arr.includes(''),arr.includes(null))//false false false
    console.log(arr.includes(89,-1),arr.includes(3,-2))//false true

    console.log(arr.myIncludes(433),arr.myIncludes(3))//false true
    console.log([].myIncludes(6),arr.myIncludes(''),arr.myIncludes(null))//false false false
    console.log(arr.myIncludes(89,-1),arr.myIncludes(3,-2))//false true

三。 Array.prototype.push

array.push(element0, element1,...,elementN);

 Array.prototype.myPush = function(){
        console.log('Array环境',this, arguments)
        for(var i=0;i<arguments.length;i++){
            this[this.length] = arguments[i]
        }
        //返回数组长度
        return this.length
    }

    var arr = [1,2,3]
    console.log(arr.push('add'))//4
    console.log(arr.myPush('myPush'))//5
    console.log(arr.myPush('str1','str2','str3'))//8
    
    console.log('myPush',arr)
    //[1, 2, 3, 'add', 'myPush', 'str1', 'str2', 'str3']

四。 Array.prototype.pop

array.pop();

Array.prototype.myPop = function(){
        //当数组为空时返回 undefined
        if(!this.length) return undefined
        var last = this[this.length-1];
        this[this.length-1]=null;
        this.length=this.length-1; 
        // //返回最后一个元素
        return last
    }

   

    var arr = [1,2,3,4,5]
    console.log(arr.pop())//5
    console.log([].pop())//undefined
   
    console.log(arr.myPop())//4
    console.log([].myPop())//undefined
    
    console.log('myPop',arr)//[1, 2, 3]

五。 Array.prototype.shift

array.shift();

Array.prototype.myShift = function(){
        if(this.length==0) return undefined
        var first = this[0]
        for(var i=0;i<this.length;i++){
            this[i]=this[i+1]
        }
        this.length= this.length-1;
        return  first
    }

   var arr = ['red','green','white','skyblue']
   console.log(arr.shift(),arr)
   console.log(arr.myShift(),arr)
   // red  ['green', 'white', 'skyblue']
   //green  ['white', 'skyblue']

六。 Array.prototype.unshift

array.unshift();

array.unshift(element0, element1,...,elementN);

 Array.prototype.myUnshift = function(){
         // 方法1
         // 第一个for循环就是把原有的元素往后挪
         for(var i=this.length+arguments.length-1;i>arguments.length-1;i--){ 
            this[i]=this[i-arguments.length]; 
         }
         //第二个for循环按顺序在数组头部插入
        for(var k=0;k<arguments.length;k++){
            this[k]=arguments[k];
        }
       
        // 方法2
        // var original = JSON.parse(JSON.stringify(this))
        // for(var i=0;i<arguments.length+original.length;i++){
        //     this[i]=i<arguments.length ?arguments[i]:original[i-arguments.length]
        // }
       
        return  this.length
    }

   var arr = ['red','green','white','skyblue']
   console.log(arr.unshift('a','b'),arr)
   console.log(arr.myUnshift(1,3,2),arr)
  // 6  ['a', 'b', 'red', 'green', 'white', 'skyblue']
  // 9   [1, 3, 2, 'a', 'b', 'red', 'green', 'white', 'skyblue']

七。Array.prototype.slice

array.slice();

array.slice(start = 0, end = this.length);

Array.prototype.mySlice = function(start,end){
         //start包含,end不包含
         var result = []
         end = end || this.length
        for(var i=start || 0;i<this.length;i++){
           if(i<end){
            result.push(this[i])
           }
          
        }
        return  result
    }

   var arr = ['red','green','white','skyblue']
   console.log([].slice(),arr.slice(),arr.slice(2),arr.slice(1,3),arr.slice(1,13),arr.slice(11,13),arr)
   console.log([].mySlice(),arr.mySlice(),arr.mySlice(2),arr.mySlice(1,3),arr.mySlice(1,13),arr.mySlice(11,13),arr)

八。迭代方法:Array.prototype.forEach

array.forEach(callbackFn, thisArg);

Array.prototype.myForEach = function(fn){
       for(var i=0;i<this.length;i++){
        //讲元素传给回调函数
          fn(this[i],i,this)
       }
    }

   var arr = ['red','green','white','skyblue']
   
   arr.forEach(function(v,index,array){
        console.log(v,index,array)
        return index
    })
   

    arr.myForEach(function(v,index,array){
        console.log(v,index,array)
    })

九。Array.prototype.map

array.map(callbackFn, thisArg);

array.map((element,index,array), thisArg)

 Array.prototype.myMap = function(fn){
       var result=[]
       for(var i=0;i<this.length;i++){
        result.push(fn(this[i],i,this)) 
       }
       return  result
    }

   var arr = ['red','green','white','skyblue']
   
   var newArr= arr.map(function(v,index,array){
        return v+(index+1)
    })
   console.log('newArr',newArr)
   //['red1', 'green2', 'white3', 'skyblue4']
   
   var newMap= arr.myMap(function(v,index,array){
        return v+(index+1)
    })
    console.log('newMap',newMap)
   //['red1', 'green2', 'white3', 'skyblue4']

十。Array.prototype.filter

array.filter(callbackFn, thisArg);

array.filter((element,index,array), thisArg)

  Array.prototype.myFilter = function(fn){
       var result=[]
       for(var i=0;i<this.length;i++){
         let res = fn(this[i],i,this)
         if(res){
            result.push(this[i]) 
         }
       }
       return  result
    }

   var arr = ['red','green','white','skyblue']
   
   var newArr= arr.filter(function(v,index,array){
        return index>1
    })
   console.log('newArr',newArr)
   // ['white', 'skyblue']
   
   var newMy= arr.myFilter(function(v,index,array){
         return index>1
    })
    console.log('newMy',newMy)
   // ['white', 'skyblue']

十一。Array.prototype.every

 Array.prototype.myEvery = function(fn){
       for(var i=0;i<this.length;i++){
         if( !fn(this[i],i,this)){
            return  false
         }
       }
       return  true
    }

   var arr = ['red','green','white','skyblue']
   
   var newArr= arr.every(function(v,index,array){
        return  v.length>1
    })
   console.log('newArr',newArr)
   //true
   
   var newMy= arr.myEvery(function(v,index,array){
         return v.length>1
    })
    console.log('newMy',newMy)
   // true

十二。Array.prototype.some

Array.prototype.mySome = function(fn){
       for(var i=0;i<this.length;i++){
         if( fn(this[i],i,this)){
            return  true
         }
       }
       return  false
    }

   var arr = ['red','green','white','skyblue']
   
   var newArr= arr.some(function(v,index,array){
        return  v.length>6
    })
   console.log('newArr',newArr)
   //true
   
   var newMy= arr.mySome(function(v,index,array){
         return  v.length>6
    })
    console.log('newMy',newMy)
   // true

十三。Array.prototype.sort

array.sort(); array.sort(compareFn); 
    Array.prototype.mySort = function(fn){
        for(var i=0; i<this.length;i++){
            for( var j=0; j<this.length-1-i;j++){
                // console.log(j,[this[j+1],this[j]])
                let result = fn(this[j],this[j+1])
                if(result>0){
                    [this[j],this[j+1]] = [this[j+1],this[j]]
                    // console.log([this[j],this[j+1]] )
                }
            }
        }
        return  this
    }

   var arr = ['red','green','white','skyblue']
   var array1 = [45,3,78,23,56,12]
   array1.sort(function(a,b){return b-a})
   console.log(array1);//[78, 56, 45, 23, 12, 3]
   array1.mySort(function(a,b){return a-b});
   console.log(array1);  //[3, 12, 23, 45, 56, 78]

十四。Array.from

Array.myFrom = function (arrayLike, fn, thisArg) {
        if(typeof arrayLike=='string' &&  typeof fn !=='function'){
             return arrayLike.split('')
        }
        if(arrayLike.length>0 &&  typeof fn !=='function'){
             return arrayLike
        }
        var result = []
        for (var i = 0; i < arrayLike.length; i++) {
            result.push(fn(arrayLike[i]))
        }
        return result
    }

    var arr = [14, 32, 123]
    console.log(Array.from('foo'));
    console.log(Array.from(arr, (x) => x*10 + 'x'));
    console.log('Array.myFrom',Array.myFrom('foo'));
    console.log('Array.myFrom',Array.myFrom('foo', (x) => x + 'x'));
    //  ['f', 'o', 'o']
    // ['140x', '320x', '1230x']

十五。Array.prototype.slice.call

Array.prototype.slice.call() 能将具有length属性的对象转成数组,比如类数组(arguments,NodeList)、字符串(String)

function test(a, b, c, d) {
        console.log(arguments)//Arguments(4) ['a', 'b', 'c', 'd', callee: (...), Symbol(Symbol.iterator): ƒ]
        // 直接调用报错
        // console.log(arguments.slice(2));//arguments.slice is not a function
        //使用call改变this指向,让arguments的具有Array的slice方法
        return Array.prototype.slice.call(arguments, 2);

    }
    console.log(test("a", "b", "c", "d")); // ['c', 'd']
    console.log(Array.prototype.slice.call('string', 3)) // ['i', 'n', 'g']
    console.log(('string').slice(3))//ing

    //类数组需要对象里面包含length,属性里面有对应length的number 0,1等
    console.log(Array.prototype.slice.call({ 0: 'obj1', 1: 'obj2', 2: 'obj3', length: 2 }));  // ["obj1", "obj2"]
    console.log(Array.prototype.slice.call({ 0: 'obj1', 1: 'obj2', 2: 'obj3' }));  // []
    console.log(Array.prototype.slice.call({ a: 'obj1', b: 'obj2' }));  // []

参考文献

zhuanlan.zhihu.com/p/386894552

www.jianshu.com/p/62eb53a44…

blog.csdn.net/weixin_4183…

zhuanlan.zhihu.com/p/485338593

blog.csdn.net/cxxhhzsl/ar…