จัดโครงสร้างโค้ดของคุณด้วย currying การประกอบฟังก์ชัน และข้อมูลที่ไม่เปลี่ยนแปลง เพื่อให้ได้ความคาดเดาได้และการทดสอบได้
เปิดบทเรียนนี้ใน KodokonJavaScript ปฏิบัติต่อฟังก์ชันในฐานะ ค่าชั้นหนึ่ง ซึ่งเปิดประตูสู่ functional pattern 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 นับเฉพาะพารามิเตอร์ที่อยู่ ก่อน พารามิเตอร์ default หรือ rest ตัวแรกเท่านั้น (a, b = 1) => {} มี length เป็น 1 ส่วน (...args) => {} เป็น 0 ดังนั้น curry ที่อิง arity จึงต้องได้รับฟังก์ชันที่มีพารามิเตอร์แบบเรียบง่าย Composition คือขั้นถัดไป: การประกอบฟังก์ชัน pure เล็ก ๆ เข้าเป็น pipeline ที่อ่านง่าย
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 ใช้จากขวาไปซ้าย เหมือนสัญกรณ์ทางคณิตศาสตร์ pipeline เหล่านี้จะมีคุณค่าก็ต่อเมื่อฟังก์ชันเป็น pure เท่านั้น - ไม่มี side effect ไม่มี dependency ที่ซ่อนอยู่ - ซึ่งเรียกร้อง ข้อมูลแบบ immutable: แทนที่จะ mutate อ็อบเจกต์ คุณสร้างเวอร์ชันใหม่ของมัน แล้วความเท่ากันของการอ้างอิงก็เพียงพอที่จะตรวจจับการเปลี่ยนแปลง (หัวใจของ reconciliation ใน 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 ใช้ได้กับ arrow function เท่านั้นpipe(f, g, h)(x) เทียบเท่ากับอะไร?const s = Object.freeze({ a: { b: 1 } }) การกำหนดค่า s.a.b = 2 ทำงานหรือไม่?s.a ไม่ได้ถูกแช่แข็ง