هيكل كودك باستخدام currying وتركيب الدوال والبيانات اللامتغيرة لتكسب قابلية التنبؤ والاختبار.
افتح هذا الدرس في Kodokonتعامل JavaScript الدوال كـ قيم من الدرجة الأولى، مما يفتح الباب للأنماط الوظيفية. يحول currying دالة ذات n وسائط إلى سلسلة من دوال أحادية الوسيط: f(a, b, c) يصبح f(a)(b)(c). لا تخلط بينه وبين التطبيق الجزئي (partial application)، الذي يثبت بعض الوسائط في خطوة واحدة (fn.bind(null, a)). يتألق currying في إنشاء دوال متخصصة من دوال عامة.
const curry = (fn) => {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) return fn(...args);
return (...rest) => curried(...args, ...rest);
};
};
const add3 = (a, b, c) => a + b + c;
const addCurried = curry(add3);
console.log(addCurried(1)(2)(3)); // 6
console.log(addCurried(1, 2)(3)); // 6دقة في المواصفة: fn.length يعد فقط الوسائط الموجودة قبل أول وسيط افتراضي أو وسيط باقٍ (rest). (a, b = 1) => {} طوله 1، و(...args) => {} طوله 0. لذا يجب إعطاء curry القائم على عدد الوسائط دوال ذات وسائط بسيطة. التركيب (composition) هو الخطوة التالية: تجميع دوال صغيرة نقية في خطوط أنابيب قابلة للقراءة.
const pipe = (...fns) => (input) =>
fns.reduce((acc, fn) => fn(acc), input);
const trim = (s) => s.trim();
const lower = (s) => s.toLowerCase();
const dashes = (s) => s.replace(/\s+/g, "-");
const toSlug = pipe(trim, lower, dashes);
console.log(toSlug(" Hello World "));
// "hello-world"pipe(f, g, h)(x) يحسب h(g(f(x))): تقرؤه بترتيب التنفيذ. المتغير compose يطبق من اليمين إلى اليسار، مثل التدوين الرياضي. لا تكون هذه الأنابيب قيّمة إلا إذا كانت الدوال نقية - دون آثار جانبية، دون تبعيات خفية - وهو ما يستدعي بيانات لامتغيرة: بدلا من تغيير كائن، تنتج نسخة جديدة منه، وعندها تكفي مساواة المراجع لكشف التغيير (قلب مصالحة React).
const state = Object.freeze({
user: { name: "Ada" },
tags: ["js"]
});
const next = {
...state,
tags: [...state.tags, "fp"]
};
const deepCopy = structuredClone(state);
deepCopy.user.name = "Grace"; // independent copybind، وcurrying فقط مع الدوال السهميةpipe(f, g, h)(x)؟const s = Object.freeze({ a: { b: 1 } })، هل يعمل الإسناد s.a.b = 2؟s.a غير مجمد