原生 JavaScript 实现各种 数组 API 的 Polyfill 版

更新日期: 2022-01-16阅读: 913标签: api

api

数组的 API 有很多,我这里放一些常用的。

本文不是具体讲某个 API 的基本用法,所以对这些 API 用法不太熟悉的同学需要先自行学习。另外大部分实现,在 MDN 上都有。

前往 —> MDN 学习基础用法。

在正式开始实现之前,先看一个例子。

let arr = [];
arr[3] = 3;
// arr.length ? arr[0] ?  0 in arr ?

// 4  undefined  fasle

这个东西在后面的实现中会出现,所以大家先了解一下。数组的下标不一定是连续的,直接赋值还会影响它的长度。

forEach

简单实现

// forEach 支持传入两个参数,callback、thisArg
// callback 返回3个参数,当前元素、当前元素索引、原数组
// thisArg 传入后,改变 callback 的 this 指针
Array.prototype.myforeach = function (fn, context = null) {
    let index = 0;
    let arr = this;
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < arr.length) {
        if (index in arr) { // 数组的下标并不一定是连续的
            fn.call(context, arr[index], index, arr);
        }
        index ++;
    }
};

支持 async/await

之前见大佬们讨论过这个问题,所以提一下。forEach 在正常情况像下面这么写肯定是做不到同步的,程序不会等一个循环中的异步完成再进行下一个循环。原因很明显,在上面的模拟中,while 循环只是简单执行了 callback,所以尽管 callback 内使用了 await ,也只是影响到 callback 内部。

arr.myforeach(async v => {
    await fetch(v);
});

要支持上面这种写法,只要稍微改一下就好。

Array.prototype.myforeach = async function (fn, context = null) {
    let index = 0;
    let arr = this;
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < arr.length) {
        if (index in arr) {
            try {
                await fn.call(context, arr[index], index, arr);
            } catch (e) {
                console.log(e);
            }
        }
        index ++;
    }
};

map

map 的实现大体和 forEach 类似,只是返回了一个新数组。

// 参数和forEach一样
// callback 需要有一个返回值
Array.prototype.mymap = function (fn, context = null) {
    let arr = this;
    let len = arr.length;
    let index = 0;
    let newArr = [];
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            let result = fn.call(context, arr[index], index, arr);
            newArr[index] = result; // 返回值作为一个新数组
        }
        index ++;
    }
    return newArr;
};

reduce

reduce 稍微麻烦一些,需要根据第二个参数是否存在,使用不同的处理方式。

Array.prototype.myreduce = function (...arg) {
    let arr = this;
    let len = arr.length;
    let index = 0;
    let fn = arg[0], result;
    if (arg.length >= 2) { // 判断是否有第二个参数,有的话作为回调函数运行的初始值
        result = arg[1];
    } else {
        // reduce 在没有第二个参数的时候,会把数组的第一项作为回调的初始值
        // 第一项并不一定是 a[0]
        while (index < len && !(index in arr)) {
        // 下标小于数组长度且下标不属于该数组就一直循环,用来找到数组的第一项
            index++;
        }
        if (index >= len) { // 如果第一项大于等于数组长度,则说明是空数组
            throw new TypeError( '空数组且没有初始值' );
        }
        result = arr[index++]; // 赋值之后下标+1
    }
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            result = fn(result, arr[index], index, arr); // 每次回调的返回值,都会传入下次回调
        }
        index ++;
    }
    return result;
};

reduce 实现一个 map

经常会有面试问到这道题,顺便写一下。

Array.prototype.mapByreduce = function (fn, context = null) {
    let arr = this;
    if (typeof fn !== 'function') {
         throw new TypeError(fn + ' is not a function');
    }
    return arr.reduce((pre, cur, index, array) => {
        let res = fn.call(context, cur, index, array);
        return [...pre, res]; // 返回一个新数组
    }, []);
};

filter

filter 一般用来筛选。

Array.prototype.myfilter = function (fn, context = null) {
    let arr = this;
    let len = arr.length;
    let index = 0, k = 0;
    let newArr = [];
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            let result = fn.call(context, arr[index], index, arr);
            if (result) newArr[k++] = arr[index]; // 如果返回值为真,就添加进新数组
        }
        index ++;
    }
    return newArr;
};

find 和 findIndex

find 和 filter 很类似,找到一个就返回当前元素,找不到返回 undefined。

findIndex 找到返回下标,找不到返回 -1。和 indexOf 类似,区别是支持回调。

Array.prototype.myfind = function (fn, context = null) {
    let arr = this;
    let len = arr.length;
    let index = 0;
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            let result = fn.call(context, arr[index], index, arr);
            if (result) return arr[index]; // 满足条件就返回
        }
        index ++;
    }
    return undefined;
};

some

some 和 find,除了返回值有区别,其他的可以说都一样。

Array.prototype.mysome = function (fn, context = null) {
    let arr = this;
    let len = arr.length;
    let index = 0;
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            let result = fn.call(context, arr[index], index, arr);
            if (result) return true; // 找到一个满足的,立即返回true
        }
        index ++;
    }
    return false; // 找不到返回 false
};

every

跟 some 相比,每个成员都满足条件才返回 true,有一个不满足就返回 false。

Array.prototype.myevery = function (fn, context = null) {
    let arr = this;
    let len = arr.length;
    let index = 0;
    if (typeof fn !== 'function') {
        throw new TypeError(fn + ' is not a function');
    }
    while (index < len) {
        if (index in arr) {
            let result = fn.call(context, arr[index], index, arr);
            if (!result) return false; // 有一个不满足,就返回false
        }
        index ++;
    }
    return true;
};

刚刚接连几个 filter、find、some、every 在实现和功能上都很相似,只是返回值上有一些差别,所以更要在合适的场景使用合适的方法。

includes 和 indexOf

这两个都可以用来查找数组中是否有某个元素,只是返回值有区别。

Array.prototype.myincludes = function (val, fromIndex = 0) {
    let arr = this;
    let len = arr.length;
    let k = Math.max(fromIndex >= 0 ? fromIndex : len - Math.abs(fromIndex), 0);
    // 允许传入负数,意为从倒数第几位开始查找
    // 负数依然是按升序查找
    // 避免传入负数绝对值大于len而使k出现负数,k设置最小值 0 
    function check(x, y) {
        return x === y ||
        (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
        // 判断 NaN
    }
    while (k < len) {
        if (k in arr) {
            if (check(val, arr[k])) return true; // 找到一个符合条件的,返回 true
        }
        k ++;
    }
    return false; // 没找到 返回false
};
// indexOf 不支持查找 NaN 
Array.prototype.myindexOf = function (val, fromIndex = 0) {
    let arr = this;
    let len = arr.length;
    let k = Math.max(fromIndex >= 0 ? fromIndex : len - Math.abs(fromIndex), 0);
    // 处理负数
    while (k < len) {
        if (k in arr) {
            if (val === arr[k]) return k; // 找到返回下标
        }
        k ++;
    }
    return -1; // 找不到返回 -1
};

join

使用连接符,将数组转成字符串

Array.prototype.myjoin = function (connector = ',') {
    let arr = this;
    let len = arr.length;
    let str = '';
    let k = 0;
    while (k < len) {
        if (k in arr) {
            if (k === len -1) { // 最后一位不用连接
                str += arr[k];
            } else {
                str += arr[k] + connector.toString();
            }
        }
        k ++;
    }
    return str;
};

好了,大致就写这些

来自:https://github.com/wuyawei/fe-code/blob/master/tiku/1.md

链接: https://fly63.com/article/detial/11182

浏览器中的图像识别 API

在 Native 开发中,Android 和 IOS 平台都在系统层面直接提供给了应用开发识别图像的一些能力,比如对于二维码/条形码的识别,Android 可以使用 barcode API 、 iOS 可以使用 CIQRCodeFeature API 。

JavaScript的API设计原则

Js的API设计原则总共包含了七个大块。系卤煮自己总结的一些经验和教训。本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来。很难做到详尽充实,如果有好的建议或者不对的地方,还望不吝赐教斧正。

适合写api接口文档的管理工具有哪些?

现在越来越流行前后端分离开发,使用ajax交互。所以api接口文档就变的十分有意义了,目前市场有哪些比较优秀的接口文档管理工具呢?比如:MinDoc,eoLinker,apizza,RAML,Swagger等等

前后端分离,如何防止api接口被恶意调用或攻击

无论网站,还是App目前基本都是基于api接口模式的开发,那么api的安全就尤为重要了。目前攻击最常见的就是“短信轰炸机”,由于短信接口验证是App,网站检验用户手机号最真实的途径,使用短信验证码在提供便利的同时,也成了呗恶意攻击的对象,那么如何才能防止被恶意调用呢?

JSON API免费接口_ 免费的天气预报、地图、IP、手机信息查询、翻译、新闻等api接口

整理提供最新的各种免费JSON接口,其中有部分需要用JSONP调用。方面前端同学的学习或在网站中的使用,包括:免费的天气预报、地图、IP、手机信息查询、翻译、新闻等api接口

什么是RESTful API?

要弄清楚什么是RESTful API,首先要弄清楚什么是REST。REST -- REpresentational State Transfer,英语的直译就是“表现层状态转移”。如果看这个概念,估计没几个人能明白是什么意思。

认识 Fetch API

Fetch API 已经作为现代浏览器中异步网络请求的标准方法,其使用 Promise 作为基本构造要素。Fetch 在主流浏览器中都有很好的支持,除了IE。

用一个通俗的例子讲清楚API

随着移动互联网的发展, 基于互联网的应用正变得越来越普及,在这个过程中,更多的平台将自身的资源开放给开发者来调用。对外提供的API 调用使得平台之间的内容关联性更强,同时这些开放的平台也为用户、开发者和中小网站带来了更大的价值。

docker提供api访问

环境centos,添加deamon.json后,dockerd命令可以启动docker,这时请求 127.0.0.1:2375 可以正常访问,使用systemctl无法启动docker的情况.无法启动docker:查看当前的docker配置

构建API的最佳编程语言是什么?

你是否正在设计第一个Web应用程序?也许你过去已经建立了一些,但是目前也正在寻找语言的变化以提高你的技能,或尝试新的东西。有了所有信息,就很难决定为下一个产品或项目选择哪种编程语言。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!