2.5 מערכים הרצאה
מה זה מערך - array¶
מערך הוא רשימה מסודרת של ערכים. זה המקבילה של list בפייתון.
const fruits = ["apple", "banana", "cherry"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, [1, 2]]; // can mix types, like Python
const empty = [];
# Python equivalent
# fruits = ["apple", "banana", "cherry"]
# numbers = [1, 2, 3, 4, 5]
# mixed = [1, "hello", True, None, [1, 2]]
# empty = []
יצירת מערכים¶
// literal syntax (recommended)
const colors = ["red", "green", "blue"];
// Array constructor (less common)
const arr1 = new Array(3); // creates array with 3 empty slots
const arr2 = new Array(1, 2, 3); // creates [1, 2, 3]
// Array.from (useful for converting things to arrays)
const chars = Array.from("hello"); // ["h", "e", "l", "l", "o"]
const range = Array.from({length: 5}, (_, i) => i); // [0, 1, 2, 3, 4]
- כמעט תמיד משתמשים בסוגריים מרובעים
[]ליצירת מערכים Array.from("hello")דומה ל-list("hello")בפייתוןArray.from({length: 5}, (_, i) => i)יוצר מערך כמוlist(range(5))בפייתון
בדיקה אם משהו הוא מערך¶
console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray("hello")); // false
console.log(Array.isArray({a: 1})); // false
typeof [1,2,3]מחזיר"object"- לא עוזר!- משתמשים ב-
Array.isArray()כדי לבדוק אם משהו הוא מערך - בפייתון:
isinstance([1,2,3], list)
גישה לאיברים¶
לפי אינדקס¶
const fruits = ["apple", "banana", "cherry", "date"];
console.log(fruits[0]); // "apple" (first element)
console.log(fruits[1]); // "banana"
console.log(fruits[3]); // "date" (last element)
console.log(fruits[10]); // undefined (no error, just undefined!)
בפייתון fruits[10] זורק IndexError. ב-JS מקבלים undefined - צריך להיזהר!
אינדקס שלילי עם at()¶
בפייתון אפשר לגשת לאיברים מהסוף עם אינדקס שלילי: fruits[-1]. ב-JS אינדקס שלילי לא עובד עם סוגריים מרובעים, אבל יש את המתודה at():
const fruits = ["apple", "banana", "cherry", "date"];
// negative index with brackets - doesn't work!
console.log(fruits[-1]); // undefined (not "date"!)
// .at() method - supports negative indices (like Python!)
console.log(fruits.at(0)); // "apple"
console.log(fruits.at(-1)); // "date" (last element)
console.log(fruits.at(-2)); // "cherry" (second to last)
אורך המערך - length¶
lengthהוא property, לא פונקציה - בלי סוגריים!- בפייתון זה
len(fruits)- פונקציה
// access last element
console.log(fruits[fruits.length - 1]); // "cherry"
// or
console.log(fruits.at(-1)); // "cherry" (cleaner)
שינוי ערכים¶
const fruits = ["apple", "banana", "cherry"];
fruits[1] = "blueberry"; // change second element
console.log(fruits); // ["apple", "blueberry", "cherry"]
- אפשר לשנות איברים במערך גם אם הוא
const constמונע שינוי של ההפניה (reference), לא של התוכן- זה כמו בפייתון -
fruits = ["new list"]לא עובד, אבלfruits[0] = "new"עובד
מתודות שמשנות את המערך - mutating methods¶
push ו-pop - הוספה והסרה מהסוף¶
const fruits = ["apple", "banana"];
// push - add to end (like Python's append)
fruits.push("cherry");
console.log(fruits); // ["apple", "banana", "cherry"]
fruits.push("date", "elderberry"); // can add multiple!
console.log(fruits); // ["apple", "banana", "cherry", "date", "elderberry"]
// pop - remove from end (like Python's pop)
const last = fruits.pop();
console.log(last); // "elderberry"
console.log(fruits); // ["apple", "banana", "cherry", "date"]
unshift ו-shift - הוספה והסרה מההתחלה¶
const fruits = ["banana", "cherry"];
// unshift - add to beginning (no Python equivalent method)
fruits.unshift("apple");
console.log(fruits); // ["apple", "banana", "cherry"]
fruits.unshift("aaa", "bbb"); // can add multiple!
console.log(fruits); // ["aaa", "bbb", "apple", "banana", "cherry"]
// shift - remove from beginning (no Python equivalent method)
const first = fruits.shift();
console.log(first); // "aaa"
console.log(fruits); // ["bbb", "apple", "banana", "cherry"]
בפייתון אין מקבילה ישירה. הדבר הקרוב:
שימו לב: unshift ו-shift איטיים במערכים גדולים כי צריך להזיז את כל האיברים. push ו-pop מהירים.
splice - הסוויס-ארמי-נייף של מערכים¶
splice יכול להוסיף, להסיר, ולהחליף איברים בכל מקום במערך:
const fruits = ["apple", "banana", "cherry", "date", "elderberry"];
// remove 2 elements starting at index 1
const removed = fruits.splice(1, 2);
console.log(removed); // ["banana", "cherry"]
console.log(fruits); // ["apple", "date", "elderberry"]
// insert elements at index 1 (remove 0 elements, add new ones)
fruits.splice(1, 0, "blueberry", "cantaloupe");
console.log(fruits); // ["apple", "blueberry", "cantaloupe", "date", "elderberry"]
// replace 1 element at index 2
fruits.splice(2, 1, "REPLACED");
console.log(fruits); // ["apple", "blueberry", "REPLACED", "date", "elderberry"]
התחביר: array.splice(startIndex, deleteCount, ...itemsToAdd)
- startIndex - מאיפה להתחיל
- deleteCount - כמה איברים למחוק
- ...itemsToAdd - אופציונלי, איברים להוסיף במקום
חיפוש במערך¶
indexOf ו-includes¶
const fruits = ["apple", "banana", "cherry", "banana"];
// indexOf - returns index of first occurrence (-1 if not found)
console.log(fruits.indexOf("banana")); // 1
console.log(fruits.indexOf("grape")); // -1
// includes - returns true/false
console.log(fruits.includes("cherry")); // true
console.log(fruits.includes("grape")); // false
בפייתון:
הבדל חשוב: בפייתון index() זורק שגיאה אם לא נמצא, ב-JS indexOf() מחזיר -1.
find ו-findIndex¶
מחפשים לפי תנאי (callback):
const numbers = [1, 5, 12, 8, 3, 20, 7];
// find - returns the first element that matches
const firstBig = numbers.find(n => n > 10);
console.log(firstBig); // 12
// findIndex - returns the index of the first match
const firstBigIndex = numbers.findIndex(n => n > 10);
console.log(firstBigIndex); // 2
// if nothing found
const notFound = numbers.find(n => n > 100);
console.log(notFound); // undefined
const notFoundIndex = numbers.findIndex(n => n > 100);
console.log(notFoundIndex); // -1
דוגמה מעשית - חיפוש באובייקטים:
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
const user = users.find(u => u.name === "Bob");
console.log(user); // { name: "Bob", age: 30 }
const index = users.findIndex(u => u.age > 28);
console.log(index); // 1 (Bob is the first one over 28)
חיתוך - slice¶
slice מחזיר עותק של חלק מהמערך, בלי לשנות את המקור:
const fruits = ["apple", "banana", "cherry", "date", "elderberry"];
// slice(start, end) - from start up to (not including) end
console.log(fruits.slice(1, 3)); // ["banana", "cherry"]
console.log(fruits.slice(2)); // ["cherry", "date", "elderberry"]
console.log(fruits.slice(0, 2)); // ["apple", "banana"]
console.log(fruits.slice(-2)); // ["date", "elderberry"]
console.log(fruits.slice(1, -1)); // ["banana", "cherry", "date"]
// original array unchanged!
console.log(fruits); // ["apple", "banana", "cherry", "date", "elderberry"]
זה מאוד דומה ל-slicing בפייתון, אבל כ-method ולא בתחביר מיוחד:
# Python # JavaScript
# fruits[1:3] # fruits.slice(1, 3)
# fruits[2:] # fruits.slice(2)
# fruits[:2] # fruits.slice(0, 2)
# fruits[-2:] # fruits.slice(-2)
חשוב: slice לא משנה את המערך המקורי (immutable). splice כן משנה (mutable).
חיבור מערכים - concatenation¶
concat¶
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
console.log(arr1); // [1, 2, 3] (unchanged)
אופרטור spread - ...¶
דרך מודרנית ונפוצה יותר:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// can add elements in between
const withMiddle = [...arr1, 99, ...arr2];
console.log(withMiddle); // [1, 2, 3, 99, 4, 5, 6]
בפייתון:
# arr1 + arr2 # [1, 2, 3, 4, 5, 6]
# [*arr1, *arr2] # same thing with unpacking
# [*arr1, 99, *arr2] # [1, 2, 3, 99, 4, 5, 6]
ה-spread operator (...) ב-JS דומה ל-unpacking operator (*) בפייתון.
המרות - join ו-split¶
join - מערך למחרוזת¶
const words = ["Hello", "World", "!"];
console.log(words.join(" ")); // "Hello World !"
console.log(words.join("-")); // "Hello-World-!"
console.log(words.join("")); // "HelloWorld!"
console.log(words.join(", ")); // "Hello, World, !"
בפייתון:
שימו לב לסדר ההפוך: בפייתון ה-separator קורא ל-join, ב-JS המערך קורא ל-join.
split - מחרוזת למערך¶
split היא מתודה של מחרוזת, לא של מערך:
const sentence = "Hello World from JavaScript";
const words = sentence.split(" ");
console.log(words); // ["Hello", "World", "from", "JavaScript"]
const csv = "Alice,25,Tel Aviv";
const parts = csv.split(",");
console.log(parts); // ["Alice", "25", "Tel Aviv"]
// split every character
const chars = "hello".split("");
console.log(chars); // ["h", "e", "l", "l", "o"]
בפייתון זה אותו דבר: "Hello World".split(" ").
מיון - sort¶
אזהרה חשובה: sort() ב-JS ממיין כמחרוזות כברירת מחדל!
const fruits = ["cherry", "apple", "banana"];
fruits.sort();
console.log(fruits); // ["apple", "banana", "cherry"] - correct!
// BUT with numbers:
const numbers = [10, 5, 100, 1, 25];
numbers.sort();
console.log(numbers); // [1, 10, 100, 25, 5] - WRONG! sorted as strings!
sort()ממיר הכל למחרוזות ומשווה לפי סדר אלפביתי- לכן 100 בא לפני 25 - כי "1" בא לפני "2" בסדר אלפביתי
- זו הטעות הכי נפוצה ב-JS עם מערכים!
כדי למיין מספרים נכון, צריך פונקציית השוואה:
const numbers = [10, 5, 100, 1, 25];
// ascending order (small to large)
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 5, 10, 25, 100] - correct!
// descending order (large to small)
numbers.sort((a, b) => b - a);
console.log(numbers); // [100, 25, 10, 5, 1]
הפונקציה (a, b) => a - b מחזירה:
- מספר שלילי אם a צריך לבוא לפני b
- 0 אם הם שווים
- מספר חיובי אם b צריך לבוא לפני a
בפייתון sort() עובד נכון על מספרים כברירת מחדל:
דוגמה - מיון אובייקטים:
const users = [
{ name: "Charlie", age: 35 },
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 }
];
// sort by age
users.sort((a, b) => a.age - b.age);
// [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }, { name: "Charlie", age: 35 }]
// sort by name
users.sort((a, b) => a.name.localeCompare(b.name));
// [{ name: "Alice"... }, { name: "Bob"... }, { name: "Charlie"... }]
שימו לב: sort() משנה את המערך המקורי!
היפוך - reverse¶
reverse()משנה את המערך המקורי- בפייתון:
numbers.reverse()אוnumbers[::-1](שיוצר עותק)
אם רוצים לא לשנות את המקור:
const original = [1, 2, 3, 4, 5];
const reversed = [...original].reverse();
console.log(original); // [1, 2, 3, 4, 5] (unchanged)
console.log(reversed); // [5, 4, 3, 2, 1]
העתקת מערכים¶
העתקה שטחית - shallow copy¶
const original = [1, 2, 3];
// spread operator (most common)
const copy1 = [...original];
// slice
const copy2 = original.slice();
// Array.from
const copy3 = Array.from(original);
copy1.push(4);
console.log(original); // [1, 2, 3] (unchanged)
console.log(copy1); // [1, 2, 3, 4]
אבל - העתקה שטחית לא מעתיקה אובייקטים מקוננים:
const nested = [[1, 2], [3, 4]];
const shallowCopy = [...nested];
shallowCopy[0].push(99);
console.log(nested); // [[1, 2, 99], [3, 4]] - CHANGED!
console.log(shallowCopy); // [[1, 2, 99], [3, 4]]
- ההעתקה השטחית מעתיקה את ההפניות למערכים הפנימיים, לא את המערכים עצמם
- אותה בעיה קיימת בפייתון עם
list.copy()אוlist[:]
העתקה עמוקה - deep copy¶
const nested = [[1, 2], [3, 4]];
const deepCopy = structuredClone(nested);
deepCopy[0].push(99);
console.log(nested); // [[1, 2], [3, 4]] (unchanged!)
console.log(deepCopy); // [[1, 2, 99], [3, 4]]
structuredCloneיוצר העתקה עמוקה - כולל כל המערכים והאובייקטים המקוננים- זה חדש יחסית (2022) אבל נתמך בכל הדפדפנים המודרניים
- בפייתון:
import copy; deep = copy.deepcopy(nested)
שיטוח מערכים - flat ו-flatMap¶
flat¶
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]] (one level)
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6] (two levels)
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6] (all levels)
flat()משטח מערכים מקוננים- כברירת מחדל משטח רמה אחת
- אפשר לציין עומק, או
Infinityלשיטוח מלא
flatMap¶
משלב map ו-flat (נלמד על map בשיעור הבא):
const sentences = ["Hello World", "Good Morning"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words); // ["Hello", "World", "Good", "Morning"]
מערכים מקוננים - nested arrays¶
// matrix (2D array)
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(matrix[0]); // [1, 2, 3] (first row)
console.log(matrix[1][2]); // 6 (second row, third column)
console.log(matrix[2][0]); // 7 (third row, first column)
// iterating over a matrix
for (const row of matrix) {
for (const cell of row) {
console.log(cell);
}
}
בפייתון זה אותו דבר:
טבלת השוואה - פייתון מול JS¶
| פעולה | Python | JavaScript |
|---|---|---|
| יצירה | [1, 2, 3] |
[1, 2, 3] |
| אורך | len(arr) |
arr.length |
| הוספה לסוף | arr.append(x) |
arr.push(x) |
| הסרה מהסוף | arr.pop() |
arr.pop() |
| הוספה להתחלה | arr.insert(0, x) |
arr.unshift(x) |
| הסרה מההתחלה | arr.pop(0) |
arr.shift() |
| חיתוך | arr[1:3] |
arr.slice(1, 3) |
| חיפוש | x in arr |
arr.includes(x) |
| אינדקס | arr.index(x) |
arr.indexOf(x) |
| חיבור | arr1 + arr2 |
[...arr1, ...arr2] |
| מיון | arr.sort() |
arr.sort((a,b) => a-b) |
| היפוך | arr.reverse() |
arr.reverse() |
| מחרוזת | ",".join(arr) |
arr.join(",") |
| פיצול | s.split(",") |
s.split(",") |
| אחרון | arr[-1] |
arr.at(-1) |
| בדיקת סוג | isinstance(x, list) |
Array.isArray(x) |
| העתקה שטחית | arr.copy() |
[...arr] |
| העתקה עמוקה | copy.deepcopy(arr) |
structuredClone(arr) |
סיכום¶
- מערכים ב-JS הם כמו lists בפייתון - מסודרים, גמישים, ומכילים כל טיפוס
push/popלסוף,unshift/shiftלהתחלה,spliceלכל מקוםsliceמחזיר עותק (לא משנה מקור),spliceמשנה את המקור- אזהרה:
sort()ממיין כמחרוזות! צריך(a,b) => a-bלמספרים find/findIndexמחפשים לפי תנאי (callback)at(-1)לגישה מהסוף - כמו אינדקס שלילי בפייתון- spread
[...arr]ליצירת עותקים ולחיבור מערכים structuredCloneלהעתקה עמוקה- בשיעור הבא נלמד על המתודות המתקדמות: map, filter, reduce ועוד