آرایهها و ساختارهای داده
ایجاد و دسترسی به آرایهها، متدهای آرایه، جستوجو، مرتبسازی، پیمایش با map و filter و reduce، Destructuring و Spread در آرایهها و آرایههای نوعدار.
آرایه چیست؟
آرایه (Array) یک لیست مرتب از مقادیر است که برای نگهداری چند مقدار در یک متغیر استفاده میشود. آرایهها در جاوا اسکریپت از نوع object هستند و اندازه آنها پویاست (داینامیک).
const fruits = ["سیب", "موز", "پرتقال"];
console.log(typeof fruits); // "object"
console.log(fruits.length); // 3
console.log(Array.isArray(fruits)); // true
ایجاد آرایه
سه روش اصلی برای ساخت آرایه وجود دارد:
// 1. روش معمول (Array Literal):
const colors = ["قرمز", "سبز", "آبی"];
// 2. با سازنده Array:
const numbers = new Array(1, 2, 3);
// 3. سازنده با یک عدد (طول آرایه خالی!):
const empty = new Array(3);
console.log(empty.length); // 3 — اما همه خانهها خالیاند
// Array.of — همیشه همان مقادیر را میسازد:
const ofArr = Array.of(3);
console.log(ofArr.length); // 1 — فقط [3]
// Array.from — از چیزی شبیه آرایه، آرایه میسازد:
const fromStr = Array.from("abc"); // ["a", "b", "c"]
const fromRange = Array.from({length: 3}, (_, i) => i * 2); // [0, 2, 4]
دسترسی به عناصر
هر عنصر آرایه یک ایندکس (شماره جایگاه) دارد که از صفر شروع میشود:
const fruits = ["سیب", "موز", "پرتقال", "کیوی"];
console.log(fruits[0]); // "سیب" — عنصر اول
console.log(fruits[fruits.length - 1]); // "کیوی" — عنصر آخر
console.log(fruits.at(-1)); // "کیوی" — ایندکس منفی از آخر
console.log(fruits.at(-2)); // "پرتقال"
console.log(fruits[10]); // undefined — خارج از محدوده
// indexOf — جایگاه یک مقدار:
console.log(fruits.indexOf("موز")); // 1
console.log(fruits.indexOf("هندوانه")); // -1 — پیدا نشد
// includes — فقط وجود یا عدم وجود:
console.log(fruits.includes("موز")); // true
// indexOf با ایندکس شروع:
console.log(fruits.indexOf("موز", 2)); // -1 — از جایگاه 2 به بعد
تغییر عناصر و طول آرایه
const numbers = [10, 20, 30];
numbers[1] = 99; // [10, 99, 30]
// افزایش طول با ایندکس:
numbers[5] = 50; // [10, 99, 30, خالی, خالی, 50]
console.log(numbers.length); // 6
// کوتاه کردن آرایه با length:
numbers.length = 2; // [10, 99]
// خالی کردن کامل آرایه:
numbers.length = 0; // []
افزودن و حذف عناصر
متدهای اصلی برای دستکاری دو انتهای آرایه:
const arr = ["الف", "ب", "ج"];
// push — به آخر اضافه میکند (طول جدید را برمیگرداند):
arr.push("د"); // ["الف", "ب", "ج", "د"]
// pop — از آخر حذف میکند (عنصر حذفشده را برمیگرداند):
const last = arr.pop(); // "د"
// unshift — به ابتدا اضافه میکند:
arr.unshift("آ"); // ["آ", "الف", "ب", "ج"]
// shift — از ابتدا حذف میکند:
const first = arr.shift(); // "آ"
// splice — افزودن/حذف از هر جا:
// splice(شروع, تعداد حذف, ...موارد جدید)
const nums = [1, 2, 3, 4, 5];
nums.splice(1, 2); // حذف 2 عنصر از جایگاه 1 → [1, 4, 5]
nums.splice(1, 0, 2, 3); // درج بدون حذف → [1, 2, 3, 4, 5]
nums.splice(2, 1, "X"); // جایگزینی → [1, 2, "X", 4, 5]
// آرایه حذفشدهها را برمیگرداند:
const removed = [1, 2, 3].splice(0, 2); // [1, 2]
push، pop، shift، unshift و splice آرایه اصلی را تغییر میدهند (Mutating). اگر آرایه اولیه نباید تغییر کند، ابتدا یک کپی از آن بگیرید.برش و اتصال آرایهها
const numbers = [1, 2, 3, 4, 5];
// slice — برش بدون تغییر آرایه اصلی:
numbers.slice(1, 3); // [2, 3] — از 1 تا 3 (بدون 3)
numbers.slice(-2); // [4, 5] — دو تای آخر
numbers.slice(); // کپی کامل آرایه
// concat — اتصال آرایهها:
const a = [1, 2];
const b = [3, 4];
const merged = a.concat(b); // [1, 2, 3, 4]
const mergedAll = a.concat(b, [5], 6); // [1, 2, 3, 4, 5, 6]
// copyWithin — کپی داخلی:
// copyWithin(هدف, شروع, پایان)
[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5]
// fill — پر کردن با یک مقدار:
[1, 2, 3, 4].fill(0); // [0, 0, 0, 0]
[1, 2, 3, 4].fill(0, 1, 3); // [1, 0, 0, 4]
متد with — تغییر بدون Mutation
متد with (ES2022) نسخه جدیدی از آرایه با یک عنصر تغییر یافته برمیگرداند، بدون اینکه آرایه اصلی تغییر کند:
const arr = [1, 2, 3, 4];
const updated = arr.with(1, 99); // [1, 99, 3, 4]
console.log(arr); // [1, 2, 3, 4] — دستنخورده!
جستوجو در آرایه
متدهای پیشرفته جستوجو بر اساس یک شرط (تابع) کار میکنند:
const users = [
{ name: "علی", age: 25 },
{ name: "سارا", age: 30 },
{ name: "رضا", age: 35 },
];
// find — اولین عنصری که شرط را پاس کند:
const young = users.find(user => user.age < 30);
// { name: "علی", age: 25 }
// findIndex — جایگاه اولین عنصر پاسکننده:
const idx = users.findIndex(user => user.age === 30); // 1
// findLast — از آخر جستوجو میکند (ES2023):
const lastYoung = users.findLast(u => u.age < 36);
// { name: "رضا", age: 35 }
// findLastIndex — جایگاه از آخر:
const lastIdx = users.findLastIndex(u => u.age >= 30); // 2
// اگر پیدا نشود:
users.find(u => u.age > 100); // undefined
users.findIndex(u => u.age > 100); // -1
مرتبسازی آرایهها
متد sort بهصورت پیشفرض عناصر را به رشته تبدیل و سپس مقایسه میکند!
// خطر مرتبسازی پیشفرض:
const nums = [100, 25, 3, 1];
nums.sort();
console.log(nums); // [1, 100, 25, 3] — الفبایی نه عددی!
// مقایسهکننده عددی صحیح:
nums.sort((a, b) => a - b); // صعودی: [1, 3, 25, 100]
nums.sort((a, b) => b - a); // نزولی: [100, 25, 3, 1]
// مرتبسازی اشیا:
const products = [
{ name: "کتاب", price: 120 },
{ name: "خودکار", price: 15 },
{ name: "میز", price: 850 },
];
products.sort((a, b) => a.price - b.price);
// خودکار → کتاب → میز
// مرتبسازی رشتهای فارسی:
const names = ["زهرا", "علی", "مهدی"];
names.sort((a, b) => a.localeCompare(b, "fa"));
// toSorted — بدون تغییر آرایه اصلی (ES2023):
const original = [3, 1, 2];
const sorted = original.toSorted(); // [1, 2, 3]
console.log(original); // [3, 1, 2] — دستنخورده!
sort قدیمی آرایه اصلی را تغییر میدهد. اگر میخواهید آرایه اولیه حفظ شود، از toSorted() استفاده کنید یا ابتدا با slice() کپی بگیرید.پیمایش آرایهها
متد forEach برای اجرای یک تابع روی هر عنصر:
const fruits = ["سیب", "موز", "پرتقال"];
fruits.forEach((fruit, index) => {
console.log(index, fruit);
});
// 0 "سیب"
// 1 "موز"
// 2 "پرتقال"
// break و continue در forEach کار نمیکنند!
// برای شکستن حلقه از for...of یا some/every استفاده کنید.
map — تبدیل هر عنصر
متد map یک آرایه جدید با همان طول میسازد و هر عنصر خروجی تابع را جای عنصر قبلی میگذارد:
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8]
const squares = numbers.map(n => n ** 2);
// [1, 4, 9, 16]
// استخراج یک ویژگی از اشیا:
const users = [
{ name: "علی", email: "ali@example.com" },
{ name: "سارا", email: "sara@example.com" },
];
const emails = users.map(user => user.email);
// ["ali@example.com", "sara@example.com"]
// بازگرداندن آبجکت (خودکار در پرانتز بگذارید!):
const withIds = numbers.map((n, i) => ({ id: i, value: n }));
// [{id: 0, value: 1}, {id: 1, value: 2}, ...]
filter — فیلتر کردن عناصر
متد filter آرایه جدیدی از عناصری میسازد که شرط را پاس کنند:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6, 8]
const bigEvens = numbers.filter(n => n > 3 && n % 2 === 0);
// [4, 6, 8]
// فیلتر اشیا:
const products = [
{ name: "کتاب", price: 120, inStock: true },
{ name: "خودکار", price: 15, inStock: false },
{ name: "میز", price: 850, inStock: true },
];
const available = products.filter(p => p.inStock);
// کتاب و میز
// حذف مقادیر تکراری:
const all = [1, 2, 2, 3, 3, 3];
const unique = all.filter((n, i, arr) => arr.indexOf(n) === i);
// [1, 2, 3]
reduce — تبدیل به یک مقدار
متد reduce کل آرایه را به یک مقدار واحد تبدیل میکند:
const numbers = [1, 2, 3, 4, 5];
// جمع کل با مقدار اولیه:
const sum = numbers.reduce((acc, n) => acc + n, 0); // 15
// بزرگترین عدد:
const max = numbers.reduce((acc, n) => Math.max(acc, n), -Infinity); // 5
// شمارش تکرارها:
const words = ["سیب", "موز", "سیب", "پرتقال", "سیب"];
const count = words.reduce((acc, word) => {
acc[word] = (acc[word] || 0) + 1;
return acc;
}, {});
// { "سیب": 3, "موز": 1, "پرتقال": 1 }
// گروهبندی اشیا:
const people = [
{ name: "علی", city: "تهران" },
{ name: "سارا", city: "اصفهان" },
{ name: "رضا", city: "تهران" },
];
const byCity = people.reduce((acc, person) => {
(acc[person.city] ||= []).push(person.name);
return acc;
}, {});
// { "تهران": ["علی", "رضا"], "اصفهان": ["سارا"] }
reduceRight
مثل reduce است اما از آخر به اول پردازش میکند:
const parts = ["پایان", "وسط", "شروع"];
const sentence = parts.reduceRight((acc, p) => acc + " " + p, "");
// " شروع وسط پایان"
some و every — بررسی شرطی
const scores = [15, 18, 12, 20, 9];
// some — آیا حداقل یکی شرط را پاس میکند؟
scores.some(s => s < 10); // true — عدد 9 وجود دارد
scores.some(s => s > 100); // false
// every — آیا همه شرط را پاس میکنند؟
scores.every(s => s > 0); // true
scores.every(s => s >= 10); // false — عدد 9 رد شده
// در آرایه خالی:
[].some(x => x); // false
[].every(x => x); // true — نکته جالب!
flat و flatMap
متد flat آرایههای تو در تو را مسطح میکند:
const nested = [1, [2, 3], [4, [5, 6]]];
nested.flat(); // [1, 2, 3, 4, [5, 6]] — یک سطح
nested.flat(2); // [1, 2, 3, 4, 5, 6] — دو سطح
nested.flat(Infinity); // مسطح کامل
// flatMap — ابتدا map سپس flat با عمق 1:
const sentences = ["سلام دنیا", "جاوا اسکریپت"];
const words = sentences.flatMap(s => s.split(" "));
// ["سلام", "دنیا", "جاوا", "اسکریپت"]
// معادل با map + flat:
sentences.map(s => s.split(" ")).flat();
// حذف موارد اضافی در flatMap:
const maybe = [1, 2, 3];
const doubledOrEmpty = maybe.flatMap(n => n > 1 ? [n * 2] : []);
// [4, 6]
Destructuring آرایه
تخریب ساختار یعنی بیرون کشیدن مقادیر آرایه به متغیرهای جدا:
const rgb = [255, 128, 0];
// تخریب ساده:
const [red, green, blue] = rgb;
console.log(red); // 255
console.log(green); // 128
// رها کردن مقادیر میانی:
const [first, , third] = rgb;
console.log(third); // 0
// مقدار پیشفرض:
const [a = 10, b = 20, c = 30, d = 40] = [1, 2];
console.log(d); // 40 — مقدار پیشفرض چون وجود نداشت
// تعویض دو متغیر بدون متغیر سوم:
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
// تخریب تو در تو:
const nested = [1, [2, 3], 4];
const [p, [q, r], s] = nested;
console.log(q, r); // 2 3
// تخریب با rest:
const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
Spread در آرایهها
عملگر گسترش (...) عناصر آرایه را در جایی دیگر پخش میکند:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// کپی آرایه:
const copy = [...arr1];
// اتصال:
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// افزودن در وسط:
const withMiddle = [...arr1.slice(0, 1), 99, ...arr1.slice(1)];
// [1, 99, 2, 3]
// بهعنوان آرگومان تابع:
const numbers = [5, 2, 8];
console.log(Math.max(...numbers)); // 8
// رشته به آرایه حروف:
const chars = [..."سلام"]; // ["س", "ل", "ا", "م"]
آرایههای نوعدار (Typed Arrays)
آرایههای نوعدار برای کار با دادههای باینری استفاده میشوند و فقط اعداد یک نوع مشخص را نگه میدارند:
// انواع اصلی:
const i8 = new Int8Array([1, 2, 3]); // عدد صحیح 8 بیتی
const u8 = new Uint8Array([200, 250]); // بدون علامت 8 بیتی
const f32 = new Float32Array([1.5, 2.5]); // اعشاری 32 بیتی
const bi64 = new BigInt64Array([10n, 20n]); // BigInt 64 بیتی
// ساخت با طول مشخص:
const buffer = new ArrayBuffer(16); // 16 بایت حافظه
const int32View = new Int32Array(buffer); // 4 عدد 32 بیتی
console.log(u8.length); // 2
console.log(u8[0]); // 200
// محدودیت نوع — مقدار نامعتبر خودکار اصلاح میشود:
const clamped = new Uint8ClampedArray([300, -5]);
console.log(clamped); // [255, 0] — محدود شده به محدوده
// اکثر متدهای آرایه معمولی پشتیبانی میشوند:
const mapped = u8.map(n => n * 2); // [400, 500]
// توجه: خروجی باز هم Uint8Array است!
این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.