美文网首页
手写 JS 中常用函数的源码 ( 持续更新... )

手写 JS 中常用函数的源码 ( 持续更新... )

作者: 酷酷的凯先生 | 来源:发表于2021-01-15 16:03 被阅读0次

前言

在日常开发中,我们经常会用到一些函数,如:Arrary.map/filter/forEach 等。今天我们来一起研究下这些函数的源码,探讨探讨有没有更好的方案/方法,以便更好的理解和应用到项目中。

Function.prototype.call/apply/bind 原理

call/apply 执行函数,并改变函数的作用域。
bind 返回一个改变作用域后的函数,需要时执行新函数。

在这里我们只探讨实现的原理,写的源码原理不足以在项目中使用

Function.prototype.call = function(context = windeow, ...args){
    // this 是当前用 call 的函数,即 a.call(b),this 就是 a
    context.fn = this;
    context.fn(..args);
    delete context.fn;
}

applycall 不同的是,参数是以数组形式整体传入,call 是单个传入

Function.prototype.apply= function(context = windeow, ...args){
    // this 是当前用 call 的函数,即 a.call(b),this 就是 a
    context.fn = this;
    context.fn(args);
    delete context.fn;
}

bind 返回一个新函数

Function.prototype.bind= function(context, ...args){
    return (...newArgs) => {
        this.call(context, ..args, ...newArgs);
    }
}

instanceOf 原理

关于 instanceOf ,这里 https://www.jianshu.com/p/87ecdec2d246 有详解

function myInstanceOf(left, right){
    left = left.__proto__;
    let prototypeTmp= right.prototype;
    while(true){
        if(left === undefined || left === null){
            return false;
        }
        if(left === prototypeTmp){
            return true;
        }
        left = left.__proto__;
   }
}

new 关键字原理

new 主要做了以下几件事:

  1. 像普通函数一样形成自己的作用域(变量提升 和 形参赋值);
  2. 创建一个新对象,将 this 指向这个新对象;
  3. 执行构造函数,给新对象添加属性 和 方法;
  4. 返回新对象;
function myNew(fn, ...args){
    // 创建一个对象,让它的原型链指向 fn.prototype
    let obj = Object.create(fn.prototype);
    // 使用 Object.create([A对象]):创建一个空对象 obj,并让 obj.__proto__ 等于 A对象
    fn.call(obj, ...args);
    rerurn obj;
}

Array.prototype.forEach

调用数组的每个元素,并将元素传递给回调函数,空数组不执行回调函数。

Array.prototype.forEach = function(callBackFn){
    if(this.length < 1){
        return this;
    }
    // 遍历数组每一项
    for(let i = 0; i < this.length; i++){
        callBackFn(this[i], i, this);
    }
}

这里的 this 是指当前调用函数的数组,以下方法也是如此。

Array.prototype.map

方法按照原始数组元素顺序依次处理元素,并返回一个新数组。
返回数组中的元素为原始数组元素调用函数处理后的值,不会改变原始数组。

Array.prototype.map = function(callBackFn){
    let newArr = [];
    if(this.length < 1){
        return this;
    }
    // 遍历数组每一项
    for(let i = 0; i < this.length; i++){
        newArr.push(callBackFn(this[i], i, this))
    }
    return newArr;
}

Array.prototype.find

数组中的每个元素都调用一次函数执行:返回通过测试(函数内判断)的数组的第一个元素的值。
当数组中的元素在测试条件时返回 true 时,find() 返回符合条件的元素,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 undefined

Array.prototype.find= function(callBackFn){
    let reslut = '';
    if(this.length < 1){
        return this;
    }
    for(let i = 0; i < this.length; i++){
        if( callBackFn(this[i],i,this) ){
            return this[i];
        }
    }
}

Array.prototype.findIndex

数组中的每个元素都调用一次函数执行:返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 -1

Array.prototype.findIndex= function(callBackFn){
   if(this.length < 1){
       return this;
   }
   for(let i = 0; i < this.length; i++){
       if( callBackFn(this[i],i,this) ){
           return i;
       }
   }
   return -1;
}

Array.prototype.filter

方法按照原始数组元素顺序依次筛选符合条件的元素,并返回一个新数组。
返回数组中的元素是通过检查指定数组中符合条件的所有元素,不会改变原始数组。

Array.prototype.filter= function(callBackFn){
   const arr = [];
   if(this.length < 1){
       return this;
   }
   for(let i = 0; i < this.length; i++){
       if( callBackFn(this[i],i,this)){
          arr.push( this[i] );
       }
   }
   return arr;
}

Array.prototype.some

会依次执行数组的每个元素:用于检测数组中的元素是否满足指定条件(函数提供)。
如果有一个元素满足条件,则表达式返回 true,剩余的元素不会再执行检测。
如果没有满足条件的元素,则返回 false

Array.prototype.some= function(callBackFn){
    if(this.length < 1){
        return this;
    }
    for(let i = 0; i < this.length; i++){
        if( callBackFn(this[i],i,this)){
           return true;
        }
    }
    return false;
}

Array.prototype.every

指定函数检测数组中的所有元素:用于检测数组所有元素是否都符合指定条件(通过函数提供)。
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
如果所有元素都满足条件,则返回 true

Array.prototype.every = function(callBackFn){
    if(this.length < 1){
        return this;
    }
    for(let i = 0; i < this.length; i++){
        if( !callBackFn(this[i],i,this) ){
           return false;
        }
    }
    return true;
}

Array.prototype.reduce

接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

Array.prototype.reduce= function(callBackFn, initValue){
    let totalVal = initValue;
    if(this.length < 1){
        return this;
    }
    for(let i = 0; i < this.length; i++){
        totalVal = callBackFn(totalVal,this[i],i);  
    }
    return totalVal;
}

Array.prototype.reduce

接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

Array.prototype.reduce= function(callBackFn, initValue){
    let totalVal = initValue;
    if(this.length < 1){
        return this;
    }
    for(let i = 0; i < this.length; i++){
        totalVal = callBackFn(totalVal,this[i],i);  
    }
    return totalVal;
}

Array.prototype.includes

判断一个数组是否包含一个指定的值,如果是返回 true,否则 false

Array.prototype.includes = function(arrItem){
    if(this.length < 1){
        return false;
    }    
    for(let i = 0; i < this.length; i++){
          if(this[i] === arrItem){
              return true;
          }
    }
    return false;
}

Array.prototype.indexOf

将从头到尾地检索数组,看它是否含有对应的元素。开始检索的位置在数组 start 处或数组的开头(没有指定 start 参数时)。如果找到一个 item,则返回 item 的第一次出现的位置。
默认开始位置的索引为 0
如果在数组中没找到指定元素则返回 -1

Array.prototype.indexOf= function(arrItem, startIndex){
    if(this.length < 1){
        return false;
    }    
    for(let i = startIndex === undefined ? 0 : startIndex; i < this.length; i++){
          if(this[i] === arrItem){
              return i;
          }
    }
    return -1;
}

Array.prototype.flat

数组扁平化,把多维数组转换为一维数组

Array.prototype.flat = function(){
    let arrResult = [], that = this;
    let fn = function(arr){
        for(let i = 0; i < arr.length; i++){
            if(Array.isArray(arr[i])){
                fn(arr[i]);
                continue;
            }
            arrResult.push(arr[i]);
        }
    }
    fn(that);
    return arrResult ;
}

相关文章

网友评论

      本文标题:手写 JS 中常用函数的源码 ( 持续更新... )

      本文链接:https://www.haomeiwen.com/subject/spuiaktx.html