JS вот-вот выпустит 4 новых фичи массивов, научились хвастаться

внешний интерфейс JavaScript
JS вот-вот выпустит 4 новых фичи массивов, научились хвастаться

Автор: Ван Мин, старший инженер-разработчик отдела навигации, 360 Group

Обзор новых функций:

  • at(): массив поддерживает индексный запрос

  • Группа массивов: классификация элементов массива;

  • Поиск массива из последнего: обратный запрос массива

  • Масштабируемый и расширяемый буфер массива: буфер массива поддерживает масштабирование размера

Прежде чем мы начнем, кратко опишем все тонкости того, что произошло.

Эти новые функцииTC39организация включенаstage3а такжеstage4условие,TC39Проще говоря, это официальная организация, которая способствует развитию языка EMCAScript (широко известного как JS). Некоторые отличные предложения, такие как промисы, функции стрелок и т. д., исходят от этой организации.360集团так какTC39Один из участников участвует в этой деятельности по продвижению языка EMCAScript, поэтому я поделюсь с вами последними функциями языка здесь; наконец, я объясню статус stage3; прежде чем каждое предложение будет помещено в формальную среду языка EMCAScript, оно должно пройти 4 стадии, от 1 до 4 стадии. На этапе 3 он в основном признается членами сообщества, а следующим шагом является поддержка исследований и разработок различных производителей браузеров, Chrome, Firefox, Safari и т. д. Этап stage4 заключается в том, что он был помещен в основные браузеры и может использоваться нами. Обычно, когда мы настраиваем файл babel, мы сталкиваемся с этой концепцией этапа;

{ "presets": ["es2015", "react", "stage-3"] }

Предложение один в ()

Массивы поддерживают индексированные запросы

Раньше мы использовали[]При использовании синтаксиса предполагается, что массивы и строки поддерживают запрос элементов по индексу. Например:

const arr = [1,2,3,4,5];

console.log(arr[4])  // 5

Такое использование действительно может ввести нас в заблуждение, думая, чтоarr[4]является четвертым элементом массива запросов, но на самом деле попробуйтеarr[-1]Установлено, что полученное не определено. В EMCAScript,[]Синтаксис изначально был разработан для работы со всеми объектами, такими какarr[1], на самом деле просто ссылаясь на ключ как "1свойство объекта, которым может обладать любой объект.arr[-1]Такое написание кода кажется допустимым, но оно возвращает "-1"значение атрибута.

const arr = [1,2,3,4,5];

console.log(arr[-1])  // undefined

Предложение at() состоит в том, чтобы решить проблему, заключающуюся в том, что массивы, строки и TypedArray нельзя напрямую запрашивать по индексу. Предложение в настоящее время находится в satge4 и реализуется основными браузерами. Вы можете скопировать приведенный ниже код и попробовать его прямо в браузере.

const arr = [1,2,3,4,5];

console.log(arr.at(-2))  // 4

оценивать: в прошлом кодеarr[arr.length-1]Использование , заставит новичков или разработчиков других языков чувствовать себя странно,arr.at(index)Это, очевидно, более семантично, и это хорошее предложение.

Предложение 2 Группа массивов

для классификации элементов массива

К прототипу массива Array добавляются два метода,groupByа такжеgroupByToMap. Содержание относительно простое, и вы можете понять его непосредственно, взглянув на вариант использования, поэтому я не буду повторяться здесь.

  • groupBy

Случаи применения:

Отсортируйте элементы массива по числу «40».

let array = [23, 56, 78, 42, 11, 49]
array.groupBy((item,index) => {
    return item > 40 ? '比40大' : "比40小"
})
// {'比40大': [56, 78, 42, 49] , '比40小': [23,11]}

groupByМетод возвращает новый анонимный объект, где ключевой ключ объектаgroupByВозвращаемое значение функции обратного вызова.

если нетgroupByПредложение, мы реализовали это в прошлом:

Array.prototype.groupBy = function(callback) {
    const object = {};
    for(let i =0; i < this.length; i++) {
        let key = callback(this[i],i,this);
        if(object[key]) {
            object[key].push(this[i])
        } else {
            object[key] = [this[i]]
        }
    }
    return object;
}
  • groupByToMap

groupByToMapМетод возвращает обычную карту, где ключ картыgroupByВозвращаемое значение функции обратного вызова.

Случаи применения:

const array = [1, 2, 3, 4, 5];
const odd  = { odd: true };
const even = { even: true };
array.groupByToMap((num, index, array) => {
  return num % 2 === 0 ? even: odd;
});

// =>  Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }

если нетgroupByToMapПредложение, мы реализовали это в прошлом:

Array.prototype.groupByToMap = function(callback) {
    const mapObject = new Map();
    for(let i =0; i < this.length; i++) {
        let key = callback(this[i],i,this);
        if(mapObject.get(key)) {
            mapObject.get(key).push(this[i])
        } else {
            mapObject.set(key,[this[i]])
        }
    }
    return mapObject;
}

оценивать: В реальной разработке такой массив[ 1 , 2 , 3 , 4 , 5 ], если вы хотите разделить нечетные и четные числа, вам нужно повторно объявить объект для его хранения.

const obj = { odd: [1, 3, 5], even: [2, 4] }

а такжеgroupByПредложение вернулоnull-prototypeобъект,{ odd: [1, 3, 5], even: [2, 4] }, нет необходимости снова объявлять именованный объект.groupByToMapВозвращается обычный объект Map, который обычно более практичен.

Предложение 3 Поиск массива из последнего

Метод поиска элемента от последнего до первого в массиве

Случаи применения:

Согласно предыдущему методу написания js, если вы хотите запросить элементы массива в ретроспективном кадре.

сделай реверс сначалаreverse, переверните массив один раз, затем используйтеfindЗапрос.

const array = [{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }];

[...array].reverse().find(n => n.value % 2 === 1); 
// { value: 3 }

Или повесить метод на прототип для реализации:

Array.prototype.findLast = function(callback) {
    const len = this.length;
    for(let i = len - 1; i > 0; i--) {
        if(callback(this[i],i,this)) {
            return this[i]
        }
    }
    return -1
}

Array find from lastСхема предложения:

Метод, предусмотренный предложениемfindLast, который поддерживает массивы прямых обратных запросов.

array.findLast(n => n.value % 2 === 1); // { value: 3 }

оценивать: С точки зрения производительности уменьшена одна инверсия массива, и действительно есть видимая оптимизация. Семантически, если есть прямой запрос, должен быть и обратный запрос, который соответствует привычкам мышления людей и, как правило, более практичен.

Предложение 4 Изменяемый размер и расширяемый буфер массива

расширятьArrayBufferКонструктор, который принимает дополнительную максимальную длину, чтобы разрешить увеличение и сжатие буфера на месте.

Прежде чем вносить предложение, нужно заранее понять, чтоArrayBuffer, какую проблему он решает, как и где его использовать. Это облегчит понимание предложения. Далее представлено содержание ArrayBuffer.Я подробно отфильтровал большую часть теории.Я надеюсь, что студенты, у которых нет предыдущей подготовки в этой области, также смогут прочитать ее за один раз.ArrayBuffer.

Array BufferЭто понятие почти никогда не подвергается прямому воздействию этого понятия в повседневном развитии, но оно имеет очень тесную связь с нами.

просто понятьArray BufferМожно сказать, что это позволяет Emcascript для манипулирования пространством памяти. Он родился из-за проекта, WebGL, который требует частого общения между браузером и видеокартой. В прошлом текстовой передаче было необходимо перевести текст «Hello World», перевести 01010111 ... языки машины Это очень дорого. Производительность, и необходимо напрямую общаться в двоичной форме, и родился массив буфера;

 const buffer = new ArrayBuffer(32);

Это создает 32-байтовое пространство памяти, буфер. Есть некоторые согласованные функции, такие как сгенерированныеArrayBuffer, нельзя изменить напрямую, нужно передать Представление TypedArray и модификация представления DataView, TypedArray — это собирательное имя для серии конструкторов, которые изменяют память, напримерUint8Array,Uint16Array,Uint32Array, DataView более гибкая работаArrayBufferПосмотреть. Вероятно, потому что первоначальный дизайн должен был решить проблему рисования изображения, поэтому он был назван различными видами, и его можно было запомнить.

Ниже приведеныTypedArrayНекоторые типы данных, поддерживаемые представлениями

тип данных длина в байтах имея в виду Соответствующий тип языка C
Int8 1 8-битное целое число со знаком signed char
Int16 2 16-битное целое число со знаком short
Int32 4 32-битное целое число со знаком int
//生成12字节的内存空间
const buffer = new ArrayBuffer(12);
//用Int32Array视图读取这个内存空间
const x1 = new Int32Array(buffer);
//直接修改
x1[0] = 1;//1
//用Int8Array视图读取这个内存空间
const x2 = new Uint8Array(buffer);
x2[0]  = 2;//2
//x1的值发生变化
x1[0] // 2

Приведенный выше код создает два представления для одного и того же сегмента памяти: 32-битное целое число со знаком (Int32Arrayконструктор) и 8-битное целое число без знака (Uint8ArrayКонструктор). Поскольку два представления соответствуют одному и тому же сегменту памяти, если одно представление изменяет базовую память, это повлияет на другое представление.

Некоторое понимание ArrayBuffer

Array Bufferпредставляет собой двоичный массив, его также можно назвать конструктором, но по сути это0 1Состоит из кэш-пространства, он в основном выполняет роль буфера данных в памяти. Простое понимание состоит в том, что компьютер будет работать, то есть обрабатывается процессор.0 1Двоичные данные состоят из двоичных данных, но иногда двоичные данные поступают быстрее и больше, а процессор все еще обрабатывает другие задачи, поэтому данные должны ждать на месте.Если задачи обработки процессора выполняются быстро, но передача данных медленно, вы должны позволить процессору бездействовать в ожидании данных, что приводит к пустой трате ресурсов, ArrayBuffer действует как буферное пространство памяти. Пусть данные существуют в этом пространстве памяти в любое время, и данные и процессор не будут ждать.

Узкие места, с которыми сталкивается ArrayBuffer

токArrayBufferЕсть проблема, когда выArrayBufferКогда места недостаточно и вам нужно увеличить пространство, вам нужно вызвать метод прототипа ArrayBuffer, ArrayBuffer.prototype.slice(), который используется следующим образом

const buffer = new ArrayBuffer(8);
const newBuffer = buffer.slice(0, 3);

Приведенный выше код копирует первые 3 байта объекта буфера (начиная с 0 и заканчивая третьим байтом) для создания нового объекта ArrayBuffer.

Фактически метод среза состоит из двух шагов.分配一段新内存, вторым шагом является преобразование исходного объекта ArrayBuffer拷贝мимо.

Этот метод можно использовать один раз, но в некоторых сценариях рисования частое создание новой памяти и копирование прошлого потребует большой производительности.

Модернизация ArrayBuffer

Вышеприведенное представило ArrayBuffer и узкое место, с которым он сталкивается в настоящее время. На этот раз поговорим о предложении войти в стадию 3.

Это предложение расширяет конструктор ArrayBuffer для увеличения конфигурации максимальной и минимальной длины расширения ---maximumByteLength. переписанныйtransferметод, который можно использовать для прямой передачи пространства памяти без копирования копии памяти и последующего ее перемещения.

после ремонтаArrayBufferКонструктор

class ArrayBuffer {
    //options为配置项 
    //maximumByteLength 配置内存伸缩长度
    constructor(byteLength,[ options ]);
    
    //挪动内存
    transfer(newByteLength);
    
    //更改内存长度
    resize(newByteLength);
    
    //分离出一个不可调整大小的ArrayBuffer
    slice(start, end);
    
    //判断是否可以伸缩
    resizable();
    
    //获取配置的最大内存长度
    maximumByteLength();
    
    //获取当前内存长度
    byteLength();
}

Случаи применения:

объявить один1024 байтапамяти и установите максимальную длину памяти на1024 кв.

//增加配置项,maximumByteLength,最大内存长度允许到1024的平方
let rab = new ArrayBuffer(1024, { maximumByteLength: 1024 ** 2 });

//当前内存长度 1024字节
assert(rab.byteLength === 1024);

//最大长度 1024平方字节
assert(rab.maximumByteLength === 1024 ** 2);

//可以就地更改长度
assert(rab.resizable);

//更改内存长度
rab.resize(rab.byteLength * 2);

//内存长度发生变化
assert(rab.byteLength === 1024 * 2);

transferэто переместить память

let ab = rab.transfer(1024);

Вышеупомянутое должно переместить 1024 байта, начиная с 0

assert(rab.byteLength === 0);
assert(rab.maximumByteLength === 0);

Выше исходная память (раб) отсоединена, а память очищена.

// 内存被转移到ab
assert(!ab.resizable);
assert(ab.byteLength === 1024);

Память успешно перенесена на ab

SharedArrayBuffer

SharedArrayBufferКак следует из названия, это ArrayBuffer, которым можно поделиться.

ArrayBufferВ предложении указанSharedArrayBufferТакже были внесены изменения, позволяющие ему поддерживать растущую память.

Кратко объясните, что такоеSharedArrayBuffer.

В EMCAScript есть некоторые вычислительные задачи, которые обычно выполняются в рабочих потоках.Каждый рабочий поток изолирован друг от друга, и связь между ними должна осуществляться через postMessage.

Помимо строковых номеров, также может осуществляться обмен бинарными данными, но бинарные данные необходимо копировать и передавать в другой поток с помощью postMessage, эффективность будет ниже при большом количестве данных.es2017когда кто-то предлагает поделитьсяSharedArrayBuffer, основной поток js и рабочий поток могут совместно использовать это пространство памяти и одновременно читать и записывать данные, избегая потери производительности, вызванной копированием двоичных данных.

В реальном сценарииSharedArrayBuffer, и передать адрес памяти черезpostMessageОтправитьworker线程

// 主线程
// 新建 1KB 共享内存
const sharedBuffer = new SharedArrayBuffer(1024);
// 主线程将共享内存的地址发送出去
w.postMessage(sharedBuffer);

worker线程принять из основного потока共享地址 ---- SharedArrayBuffer, нет необходимости копировать один и тот же двоичный адрес для передачи. пройти через共享地址Улучшенная производительность.

// Worker 线程
onmessage = function (ev) {
  // 主线程共享的数据,就是 1KB 的共享内存
  const sharedBuffer = ev.data;
  // 在共享内存上建立视图,方便读写
  const sharedArray = new Int32Array(sharedBuffer);
  // ...
};

ArrayBufferпара предложенийSharedArrayBufferтакже был расширен, чтобы разрешитьSharedArrayBufferПоддержка увеличенной памяти, но сArrayBufferОтличие в том, что уменьшение памяти не поддерживается.Очевидно, что уменьшение памяти, скорее всего, повлияет на共享другие программы в этой памяти.

НижеSharedArrayBufferконструктор. существуетArrayBufferв конструктореresize, где имяgrow, также может отражать разницу между ними.

class SharedArrayBuffer {
    //和ArrayBuffer一样配置maximumByteLength
    constructor(byteLength, [ options ]);
    
    //只能增加内存,而不能缩短内存
    grow(newByteLength);
    
    //分离出一份不可增长的 SharedArrayBuffer。
    slice(start, end);

    //判断是否可以扩充内存
    growable();
    
    //获取最大内存长度
    maximumByteLength();
    
    //获取当前内存长度
    byteLength();
  }

В настоящее времяArrayBufferПредложение сталкивается с препятствием. В реальной сцене может быть несколько потоков, которым необходимо расширить память. В соответствии с текущим дизайном память должна быть сначала занята, а затем расширена или уменьшена до целевой памяти. Однако в реальной сцене может не хватать памяти, что приведет к захвату ресурсов. Поэтому проблема распределения ресурсов памяти еще требует решения.

конец

Если вас заинтересовали эти предложения, вы можете оставить сообщение для совместного обсуждения.

Выше приведены четыре предложения, представленные на этот раз.

Если это будет полезно для вас, я надеюсь, что друзья поставят лайк и перешлют его.Ваша поддержка является движущей силой для нас, чтобы продолжать продвигать новые функции языка js.

Редактор: Сяо Мин

Обзор: Сяоцзе