We are still cooking the magic in the way!
JavaScript المتقدم (ES6+)
الدوال السهمية
الدوال السهمية
الدوال السهمية هي إحدى أكثر الميزات شعبية في ES6. توفر بناء جملة أقصر لكتابة الدوال وتحل مشكلة ربط this سيئة السمعة. في هذا الدرس، سنتقن بناء جملة الدالة السهمية ونفهم متى نستخدمها.
بناء جملة الدالة السهمية والأشكال المختلفة
تستخدم الدوال السهمية بناء جملة => (ومن هنا جاء الاسم "سهم"). لنقارن الدوال التقليدية مع الدوال السهمية:
الدالة التقليدية:
function greet(name) {
return "Hello, " + name;
}
الدالة السهمية (البناء الكامل):
const greet = (name) => {
return "Hello, " + name;
};
الدالة السهمية (مختصرة):
const greet = (name) => "Hello, " + name;
أنماط مختلفة لبناء جملة الدالة السهمية:
بدون معاملات:
const sayHello = () => "Hello!";
معامل واحد (الأقواس اختيارية):
const square = x => x * x;
const double = (x) => x * 2; // الأقواس لا تزال مسموحة
عدة معاملات (الأقواس مطلوبة):
const add = (a, b) => a + b;
const multiply = (x, y, z) => x * y * z;
عدة عبارات (الأقواس المعقوفة مطلوبة):
const calculateArea = (width, height) => {
const area = width * height;
console.log("Area calculated!");
return area;
};
دليل الأسلوب: استخدم دائماً الأقواس حول المعاملات، حتى للمعاملات المفردة. هذا يجعل الكود أكثر اتساقاً وأسهل للتعديل لاحقاً.
الإرجاع الضمني مقابل الإرجاع الصريح
للدوال السهمية نمطان للإرجاع:
الإرجاع الضمني (بدون أقواس معقوفة):
const add = (a, b) => a + b; // يُرجع النتيجة تلقائياً
const getName = (user) => user.name; // يُرجع user.name
const isAdult = (age) => age >= 18; // يُرجع قيمة منطقية
الإرجاع الصريح (مع أقواس معقوفة):
const add = (a, b) => {
return a + b; // يجب استخدام الكلمة return
};
const processUser = (user) => {
console.log("Processing user...");
return user.name.toUpperCase(); // الإرجاع مطلوب
};
إرجاع كائنات حرفية يتطلب أقواساً:
خطأ (JavaScript يعتقد أنها كتلة كود):
const makePerson = (name, age) => { name: name, age: age };
// خطأ: Unexpected token ':'
صحيح (لف الكائن بأقواس):
const makePerson = (name, age) => ({ name: name, age: age });
// يُرجع: { name: "John", age: 25 }
مع اختصار الخاصية:
const makePerson = (name, age) => ({ name, age });
// نفس النتيجة، بناء جملة أنظف
خطأ شائع: نسيان الأقواس عند إرجاع كائنات حرفية هو أحد أكثر أخطاء الدالة السهمية شيوعاً!
ربط this في الدوال السهمية
هذا هو الفرق الأكثر أهمية بين الدوال السهمية والدوال العادية:
الدالة العادية (this ديناميكي):
const person = {
name: "John",
greet: function() {
console.log("Hello, " + this.name);
}
};
person.greet(); // "Hello, John" - يعمل!
const greetFn = person.greet;
greetFn(); // "Hello, undefined" - this ضائع!
الدالة السهمية (this معجمي):
const person = {
name: "John",
friends: ["Jane", "Bob"],
greetFriends: function() {
// الدالة السهمية ترث 'this' من greetFriends
this.friends.forEach(friend => {
console.log(this.name + " says hi to " + friend);
});
}
};
person.greetFriends();
// "John says hi to Jane"
// "John says hi to Bob"
الدوال السهمية ليس لديها this خاص بها - ترثه من النطاق المحيط:
مشكلة مع الدالة العادية:
const counter = {
count: 0,
increment: function() {
setInterval(function() {
this.count++; // this هو window/undefined، وليس counter!
console.log(this.count);
}, 1000);
}
};
// الإخراج: NaN, NaN, NaN...
الحل مع الدالة السهمية:
const counter = {
count: 0,
increment: function() {
setInterval(() => {
this.count++; // this يشير بشكل صحيح إلى counter
console.log(this.count);
}, 1000);
}
};
// الإخراج: 1, 2, 3, 4...
المفهوم الرئيسي: تلتقط الدوال السهمية
this من السياق المحيط بها (النطاق المعجمي)، مما يجعلها مثالية لوظائف رد الاتصال ومعالجات الأحداث.
متى تستخدم الدوال السهمية مقابل الدوال العادية
✓ استخدم الدوال السهمية:
1. وظائف رد الاتصال (map، filter، forEach، إلخ.)
2. معالجات الأحداث حيث تحتاج this الأصل
3. الوعود والعمليات غير المتزامنة
4. الدوال القصيرة والبسيطة
5. عندما تحتاج إلى ربط this معجمي
✗ تجنب الدوال السهمية:
1. طرق الكائن (تحتاج this ديناميكي)
2. الدوال التي تحتاج كائن arguments
3. البناءات (الدوال السهمية لا يمكن أن تكون بناءات)
4. عندما تحتاج إلى استخدام call() أو apply() أو bind()
5. الدوال مع طرق prototype
الدوال السهمية في وظائف رد الاتصال وطرق المصفوفات
تتألق الدوال السهمية في وظائف رد اتصال طرق المصفوفات:
الدوال التقليدية:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(n) {
return n * 2;
});
const evens = numbers.filter(function(n) {
return n % 2 === 0;
});
الدوال السهمية (أنظف بكثير):
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
التحويلات المعقدة تصبح أكثر قابلية للقراءة:
const users = [
{ name: "John", age: 25 },
{ name: "Jane", age: 30 },
{ name: "Bob", age: 20 }
];
// احصل على أسماء المستخدمين البالغين، مرتبة
const adultNames = users
.filter(user => user.age >= 21)
.map(user => user.name)
.sort((a, b) => a.localeCompare(b));
console.log(adultNames); // ["Jane", "John"]
قيود الدوال السهمية
للدوال السهمية بعض القيود:
1. لا يوجد كائن arguments:
const regular = function() {
console.log(arguments); // يعمل: [1, 2, 3]
};
regular(1, 2, 3);
const arrow = () => {
console.log(arguments); // خطأ: arguments غير معرف
};
// الحل: استخدم معاملات الباقي
const arrow = (...args) => {
console.log(args); // يعمل: [1, 2, 3]
};
arrow(1, 2, 3);
2. لا يمكن استخدامها كبناءات:
const Person = (name) => {
this.name = name;
};
const john = new Person("John"); // TypeError: Person ليست بناءً
// الحل: استخدم class أو الدالة العادية
class Person {
constructor(name) {
this.name = name;
}
}
3. لا توجد خاصية prototype:
const regularFn = function() {};
console.log(regularFn.prototype); // Object {}
const arrowFn = () => {};
console.log(arrowFn.prototype); // undefined
حالات الاستخدام في العالم الحقيقي
حالة الاستخدام 1: معالجات أحداث DOM
class TodoList {
constructor() {
this.todos = [];
this.button = document.querySelector("#addBtn");
// الدالة السهمية تحافظ على مرجع 'this'
this.button.addEventListener("click", () => {
this.addTodo("New task");
});
}
addTodo(task) {
this.todos.push(task);
}
}
حالة الاستخدام 2: سلاسل الوعود
fetch("https://api.example.com/users")
.then(response => response.json())
.then(users => users.filter(u => u.active))
.then(activeUsers => activeUsers.map(u => u.name))
.then(names => console.log(names))
.catch(error => console.error(error));
حالة الاستخدام 3: معالجة المصفوفات
const products = [
{ name: "Laptop", price: 1000, category: "electronics" },
{ name: "Phone", price: 500, category: "electronics" },
{ name: "Shirt", price: 50, category: "clothing" }
];
const expensiveElectronics = products
.filter(p => p.category === "electronics")
.filter(p => p.price > 600)
.map(p => ({ name: p.name, discount: p.price * 0.1 }));
تمرين الممارسة:
حوّل هذه الدوال العادية إلى دوال سهمية:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(n) {
return n * 2;
});
const sumAll = function(arr) {
return arr.reduce(function(sum, n) {
return sum + n;
}, 0);
};
const createUser = function(name, age) {
return {
name: name,
age: age,
greet: function() {
return "Hi, I'm " + name;
}
};
};
الحل:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const sumAll = (arr) => arr.reduce((sum, n) => sum + n, 0);
const createUser = (name, age) => ({
name,
age,
greet: () => `Hi, I'm ${name}` // القوالب الحرفية (الدرس القادم!)
});
الملخص
في هذا الدرس، تعلمت:
- تستخدم الدوال السهمية بناء جملة
=>لإعلانات دالة موجزة - الإرجاع الضمني يعمل بدون أقواس معقوفة للتعبيرات المفردة
- للدوال السهمية ربط
thisمعجمي (ترث من النطاق الأصل) - مثالية لوظائف رد الاتصال وطرق المصفوفات ومعالجات الأحداث
- لا يمكن استخدامها كبناءات أو عندما تحتاج
thisديناميكي - لا يوجد كائن
arguments(استخدم معاملات الباقي بدلاً من ذلك) - لف الكائنات الحرفية بأقواس للإرجاع الضمني
التالي: في الدرس التالي، سنستكشف القوالب الحرفية - طريقة قوية لإنشاء سلاسل مع تعبيرات مدمجة ومحتوى متعدد الأسطر!