Что такое массив и зачем он нужен?
Массив в Google Apps Script, как и в JavaScript, представляет собой упорядоченную коллекцию значений. Каждый элемент в массиве имеет свой числовой индекс, начиная с нуля. Массивы являются фундаментальной структурой данных, необходимой для хранения наборов однотипных или разнотипных данных, их итерации и обработки. Они широко используются при работе с данными из Google Таблиц, Документов, Календаря и других сервисов Google Workspace, а также при обработке ответов API.
Объявление и инициализация массивов: основы
Объявление массива в Apps Script следует стандартному синтаксису JavaScript. Можно объявить массив и сразу инициализировать его значениями:
/**
* Пример объявления и инициализации массива строк.
*/
function declareAndInitializeArray(): void {
// Объявляем массив строк с начальными значениями
const campaignNames: string[] = ["Поиск - Бренд", "КМС - Ремаркетинг", "Поиск - Общие запросы"];
Logger.log(campaignNames);
Logger.log(typeof campaignNames); // object
Logger.log(Array.isArray(campaignNames)); // true
}Использование типизации (например, : string[]) помогает улучшить читаемость кода и избежать ошибок на этапе разработки.
Создание пустого массива: основные способы
Часто возникает необходимость создать массив, который будет наполняться данными позже в процессе выполнения скрипта. Существует два основных способа создания пустого массива.
Использование литерала массива: `[]`
Самый распространенный, лаконичный и рекомендуемый способ создания пустого массива — использование литеральной нотации [].
/**
* Создание пустого массива с использованием литерала.
*/
function createEmptyArrayLiteral(): void {
// Создаем пустой массив для хранения ID конверсий
const conversionIds: number[] = [];
Logger.log(conversionIds); // Вывод: []
Logger.log(conversionIds.length); // Вывод: 0
}Этот способ прост, понятен и эффективен.
Применение конструктора `new Array()`
Альтернативный способ — использование конструктора Array().
/**
* Создание пустого массива с использованием конструктора Array().
*/
function createEmptyArrayConstructor(): void {
// Создаем пустой массив для хранения объектов отчетов
const reportObjects: object[] = new Array();
Logger.log(reportObjects); // Вывод: []
Logger.log(reportObjects.length); // Вывод: 0
}Вызов new Array() без аргументов создает пустой массив, аналогично [].
Различия между способами создания пустого массива
При создании именно пустого массива между [] и new Array() практически нет разницы в функциональности. Однако литеральная нотация [] считается более предпочтительной по нескольким причинам:
Краткость и читаемость: [] короче и интуитивно понятнее.
Производительность: В большинстве движков JavaScript литеральная нотация может быть незначительно быстрее.
Поведение конструктора с аргументами: Важно помнить, что new Array(n), где n — число, создает массив с n пустыми слотами (empty slots), а не массив с одним числовым элементом n. Это может привести к путанице. new Array("a", "b") работает аналогично ["a", "b"].
В подавляющем большинстве случаев для создания пустого массива следует использовать [].
Работа с пустым массивом: добавление элементов
После создания пустого массива его необходимо наполнить данными.
Метод `push()`: добавление элементов в конец массива
Метод push() является стандартным способом добавления одного или нескольких элементов в конец массива. Он изменяет исходный массив и возвращает его новую длину.
/**
* Добавление элементов в массив с помощью push().
*/
function addElementsWithPush(): void {
const keywords: string[] = [];
Logger.log(`Начальная длина: ${keywords.length}`); // 0
// Добавляем элементы
let newLength = keywords.push("google apps script tutorial");
Logger.log(`Добавлен элемент: ${keywords[0]}, Новая длина: ${newLength}`); // 1
newLength = keywords.push("apps script automation", "gas examples");
Logger.log(`Массив после добавления: ${keywords}`);
Logger.log(`Новая длина: ${newLength}`); // 3
}Добавление элементов по индексу
Можно добавлять элементы, присваивая значение конкретному индексу массива. Если присвоить значение индексу, равному текущей длине массива, элемент добавится в конец, аналогично push().
/**
* Добавление элементов в массив по индексу.
*/
function addElementsByIndex(): void {
const campaignData: object[] = [];
// Добавляем первый элемент (индекс 0)
campaignData[0] = { id: "C123", name: "Search Campaign", budget: 50 };
Logger.log(`Массив после индекса 0: ${JSON.stringify(campaignData)}`);
Logger.log(`Длина: ${campaignData.length}`); // 1
// Добавляем следующий элемент (индекс 1)
campaignData[1] = { id: "C456", name: "Display Campaign", budget: 30 };
Logger.log(`Массив после индекса 1: ${JSON.stringify(campaignData)}`);
Logger.log(`Длина: ${campaignData.length}`); // 2
// Осторожно: Создание 'дыр' в массиве
campaignData[5] = { id: "C789", name: "Video Campaign", budget: 70 };
Logger.log(`Массив после индекса 5: ${JSON.stringify(campaignData)}`);
Logger.log(`Длина: ${campaignData.length}`); // 6 (индексы 2, 3, 4 будут )
Logger.log(campaignData[3]); // undefined
}Присваивание значения индексу, который значительно превышает текущую длину, создает разреженный массив (sparse array), что обычно не рекомендуется.
Примеры добавления различных типов данных в пустой массив
Массивы в Apps Script могут хранить элементы различных типов данных.
/**
* Добавление различных типов данных в массив.
*/
function addMixedDataTypes(): void {
const mixedData: any[] = [];
mixedData.push("Строковый элемент"); // string
mixedData.push(123.45); // number
mixedData.push(true); // boolean
mixedData.push(null); // null
mixedData.push({ key: "value" }); // object
mixedData.push(new Date()); // Date object
Logger.log(`Смешанный массив: ${JSON.stringify(mixedData)}`);
Logger.log(`Длина: ${mixedData.length}`); // 6
}Распространенные ошибки и как их избежать
При работе с пустыми массивами можно столкнуться с некоторыми типичными ошибками.
Попытка доступа к несуществующему индексу в пустом массиве
Обращение к любому индексу пустого массива вернет undefined. Если попытаться использовать это значение в дальнейших операциях, это может привести к ошибке TypeError.
/**
* Пример ошибки при доступе к элементу пустого массива.
*/
function accessEmptyArrayError(): void {
const empty: string[] = [];
try {
const firstElement: string = empty[0];
Logger.log(firstElement); // Не выполнится, т.к. firstElement = undefined
// Ошибка возникнет при попытке использовать метод строки на undefined
Logger.log(firstElement.toUpperCase());
} catch (e) {
Logger.log(`Ошибка: ${e}`); // TypeError: Cannot read property 'toUpperCase' of undefined
}
// Правильно: проверять длину перед доступом
if (empty.length > 0) {
const firstElement: string = empty[0];
// ... работа с элементом
} else {
Logger.log("Массив пуст, доступ к элементу невозможен.");
}
}Неправильное использование методов массивов
Некоторые методы массива (например, pop(), shift(), forEach(), map(), filter()) ведут себя специфично на пустых массивах:
pop() и shift() вернут undefined и не изменят массив.
Итерационные методы (forEach, map, filter, reduce и т.д.) просто не выполнят ни одной итерации, не вызвав ошибки.
Проблема может возникнуть, если вы ожидаете, что метод вернет значение или выполнит действие, а он ничего не делает из-за пустоты массива.
Советы по отладке кода при работе с пустыми массивами
Используйте Logger.log() или console.log(): Выводите содержимое массива и его длину (array.length) в ключевых точках алгоритма, особенно перед циклами или доступом по индексу.
Проверяйте Array.isArray(): Убедитесь, что переменная действительно содержит массив.
Используйте отладчик Apps Script: Устанавливайте точки останова (breakpoints) и пошагово выполняйте код, отслеживая значения переменных.
Проверяйте длину: Перед итерацией или доступом к элементам добавьте проверку if (myArray.length > 0) { ... }.
Практические примеры использования пустых массивов
Пустые массивы часто служат контейнерами для сбора и обработки данных.
Сбор данных из таблицы Google Sheets в пустой массив
/**
* Собирает email'ы из указанного столбца таблицы Google Sheets.
* @param {string} sheetName Имя листа.
* @param {number} emailColumn Номер столбца с email (начиная с 1).
* @return {string[]} Массив email-адресов.
*/
function getEmailsFromSheet(sheetName: string = "Лист1", emailColumn: number = 3): string[] {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
if (!sheet) {
Logger.log(`Лист с именем '${sheetName}' не найден.`);
return []; // Возвращаем пустой массив, если лист не найден
}
const dataRange = sheet.getDataRange();
const values = dataRange.getValues();
const emails: string[] = []; // Создаем пустой массив для результатов
// Пропускаем заголовок (i=1)
for (let i = 1; i < values.length; i++) {
const row = values[i];
const email = row[emailColumn - 1]; // Индексация в массиве с 0
// Простая проверка на валидность email и непустое значение
if (email && typeof email === 'string' && email.includes('@')) {
emails.push(email.trim());
}
}
Logger.log(`Найдено ${emails.length} email адресов.`);
return emails;
}Фильтрация данных и добавление результатов в новый пустой массив
/**
* Фильтрует массив объектов кампаний по бюджету.
* @param {{id: string, name: string, budget: number}[]} campaigns Массив объектов кампаний.
* @param {number} minBudget Минимальный бюджет.
* @return {{id: string, name: string, budget: number}[]} Отфильтрованный массив кампаний.
*/
function filterCampaignsByBudget(campaigns: {id: string, name: string, budget: number}[], minBudget: number): {id: string, name: string, budget: number}[] {
const filteredCampaigns: {id: string, name: string, budget: number}[] = []; // Пустой массив для результатов фильтрации
for (const campaign of campaigns) {
if (campaign.budget >= minBudget) {
filteredCampaigns.push(campaign);
}
}
// Альтернатива с использованием Array.prototype.filter
// const filteredCampaigns = campaigns.filter(campaign => campaign.budget >= minBudget);
Logger.log(`Кампаний с бюджетом >= ${minBudget}: ${filteredCampaigns.length}`);
return filteredCampaigns;
}
/** Пример использования функции фильтрации */
function testCampaignFilter(): void {
const allCampaigns = [
{ id: "C1", name: "Search Low Budget", budget: 20 },
{ id: "C2", name: "Search High Budget", budget: 150 },
{ id: "C3", name: "Display Medium Budget", budget: 75 }
];
const highBudgetCampaigns = filterCampaignsByBudget(allCampaigns, 100);
Logger.log(JSON.stringify(highBudgetCampaigns));
}Обработка данных и создание массива для дальнейшего использования
Предположим, мы получили ответ от внешнего API в виде массива объектов, и нам нужно извлечь только определенные поля.
/**
* Извлекает UTM-метки из массива URL-адресов.
* @param {string[]} urls Массив URL.
* @return {{source: string | null, medium: string | null, campaign: string | null}[]} Массив объектов с UTM-метками.
*/
function extractUtmTags(urls: string[]): {source: string | null, medium: string | null, campaign: string | null}[] {
const utmResults: {source: string | null, medium: string | null, campaign: string | null}[] = []; // Пустой массив для хранения результатов
for (const urlString of urls) {
try {
const url = new URL(urlString); // Используем встроенный объект URL для парсинга
const params = url.searchParams;
const utm = {
source: params.get('utm_source'),
medium: params.get('utm_medium'),
campaign: params.get('utm_campaign')
};
utmResults.push(utm);
} catch (e) {
Logger.log(`Не удалось распарсить URL: ${urlString}. Ошибка: ${e}`);
// Можно добавить объект с null значениями или пропустить
utmResults.push({ source: null, medium: null, campaign: null });
}
}
return utmResults;
}
/** Пример использования */
function testUtmExtraction(): void {
const landingPages = [
"https://example.com/?utm_source=google&utm_medium=cpc&utm_campaign=spring_sale",
"https://example.com/about",
"https://example.com/?utm_source=facebook&utm_medium=cpm",
"invalid-url"
];
const extractedTags = extractUtmTags(landingPages);
Logger.log(JSON.stringify(extractedTags, null, 2));
}В этих примерах пустой массив инициализируется в начале, а затем динамически наполняется данными в процессе выполнения логики скрипта, что является типичным паттерном использования в Google Apps Script.