предисловие
Тип массива в JavaScript предоставляет нам множество нативных методов, которые мы можем использовать в этой статье.Реализация моделирования
Кроме того, я также постоянно учусь, если что-то не так, пожалуйста, поправьте меня, я обновлю это вовремя, спасибо.
адрес блога🍹🍰 fe-код
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 ++;
}
};
- Поддержка асинхронного/ожидания
Я видел, как большие ребята обсуждали этот вопрос раньше, поэтому я упомяну об этом. ForEach определенно не является синхронным, когда он написан следующим образом при нормальных обстоятельствах, и программа не будет ждать асинхронного завершения одного цикла, прежде чем перейти к следующему циклу. Причина очевидна: в приведенной выше симуляции цикл while просто выполняет обратный вызов, поэтому, несмотря на то, что await используется внутри обратного вызова, он влияет только на внутреннюю часть обратного вызова.
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
сокращение немного более громоздко, и его нужно обрабатывать по-разному в зависимости от того, существует ли второй параметр.
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;
};
уменьшить реализует карту
Там часто задают в интервью этот вопрос, как написать об этом.
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
фильтр обычно используется скрининг.
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 очень похож на 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
Некоторые и 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
По сравнению с некоторыми, каждый член возвращает 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;
};
Просто несколько фильтров, найти, некоторые, все похожи по реализации и функции, но есть некоторые различия в возвращаемом значении, поэтому более необходимо использовать соответствующий метод в соответствующем сценарии.
включает и 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;
};
Ну вот и все, если вы считаете нужным что-то добавить, можете мне сказать.
Справочная статья
группа обмена
Группа внешнего обмена QQ: 960807765, приветствуем все виды технического обмена, с нетерпением ждем вашего присоединения;
Группа WeChat: Студенты, кому это необходимо, могут добавить меня в друзья, я добавлю вас в группу, в конце статьи есть QR-код ^_^.
постскриптум
Если вы это видите, и эта статья вам полезна, надеюсь, вы сможете поддержать автора своими ручонками, спасибо 🍻. Если в тексте что-то не так, укажите на это и поделитесь. Хорошо, я снова потратил впустую время всех, спасибо за чтение, увидимся в следующий раз!
- Репозиторий статей 🍹🍰fe-код
- Система социальной чаты (Vue + Node + Mongodb) - 💘🍦🙈vchat
последние статьи:
- [С головы до пят] Реализация многопользовательского видеочата на фронтенде — реальный бой WebRTC (мультиплеер)
- [С головы до ног] WebRTC + Canvas реализует общую монтажную область для совместной работы двух человек | Технические документы Nuggets
- [Front-end Advanced Road, 2019] Подробный принцип адаптации Vue, анализ исходного кода
- [2019 front-end advanced road] полная версия связи между компонентами Vue
Заинтересованные студенты могут обратить внимание на мой публичный номерпередний двигатель, весело и информативно. Вы также можете добавить меня в друзья, мы можем учиться и общаться вместе ^ _ ^.