คำแนะนำที่เกี่ยวข้อง: บทช่วยสอน JavaScript
apply(context,[arguments])
, call(context,param1,param2,...)
Currying เป็นเทคนิคที่แปลงฟังก์ชันที่ยอมรับพารามิเตอร์หลายตัวให้เป็นฟังก์ชันที่ยอมรับพารามิเตอร์ตัวเดียว (พารามิเตอร์แรกของฟังก์ชันดั้งเดิม) และส่งกลับฟังก์ชันใหม่ที่ยอมรับพารามิเตอร์ที่เหลือและส่งกลับผลลัพธ์
ตัวอย่างเช่น นี่คือฟังก์ชัน add()
ซึ่งเป็นฟังก์ชันที่ใช้ในการประมวลผลการบวกและผลรวมของพารามิเตอร์ (param1, params2,...) ที่เราส่งผ่านไป
// นี่คือฟังก์ชัน `add(x, y)` ตัวแรกที่มีพารามิเตอร์สองตัว `x`, `y` ฟังก์ชัน add(x, y){ กลับ x + y; - // เรียกใช้ฟังก์ชัน `add()` และกำหนดพารามิเตอร์ 2 ตัวคือ `4` และ `6` เพิ่ม(4,6); // จำลองการทำงานของคอมพิวเตอร์ ส่งผ่านพารามิเตอร์แรก 4 ในขั้นตอนแรก เพิ่มฟังก์ชัน(4, y){ กลับ 4 + y; - // จำลองการทำงานของคอมพิวเตอร์ ส่งผ่านพารามิเตอร์แรก 6 ในขั้นตอนที่สอง ฟังก์ชั่นเพิ่ม (4, 6) { กลับ 4 + 6; }
ถ้าเรารวมเอาฟังก์ชัน add()
ไว้ด้วยจะเป็นอย่างไร? นี่เป็นการนำไปใช้อย่างง่าย:
// ฟังก์ชัน curried add() สามารถยอมรับพารามิเตอร์บางตัวได้ ฟังก์ชัน add(x,y){ ถ้า (ประเภทของ y === 'ไม่ได้กำหนด') { ฟังก์ชั่นส่งคืน (ใหม่) { กลับ x + ใหม่; - - // ส่งคืนแอปพลิเคชันแบบเต็ม x + y; - // ทดสอบการโทร console.log(typeof add(4)); // [ฟังก์ชั่น] console.log(เพิ่ม(4)(6)); // 10 // คุณสามารถสร้างฟังก์ชั่นบันทึกได้ โดยให้ saveAdd = add(4); console.log(saveAdd(6)); // 10
ดังที่เห็นได้จากฟังก์ชัน curried add()
ข้างต้น ฟังก์ชันสามารถรับฟังก์ชันบางอย่างแล้วส่งคืนฟังก์ชันใหม่เพื่อดำเนินการประมวลผลฟังก์ชันที่เหลือต่อไป
ที่นี่เราสร้างฟังก์ชัน Currying สาธารณะ เพื่อที่เราจะได้ไม่ต้องดำเนินการกระบวนการ Currying ที่ซับซ้อนภายในทุกครั้งที่เราเขียนฟังก์ชัน
//กำหนดฟังก์ชัน createCurry ฟังก์ชัน createCurry(fn){ var ชิ้น = Array.prototype.slice, Stored_args = Slice.call (อาร์กิวเมนต์,1); ฟังก์ชันส่งคืน () { ให้ new_args = Slice.call(อาร์กิวเมนต์) args = store_args.concat (new_args); กลับ fn.apply (null, args); }}
ในฟังก์ชันการแกงสาธารณะข้างต้น:
arguments
ไม่ใช่อาเรย์จริง แต่เป็นอ็อบเจ็กต์ที่มีแอตทริบิวต์ length
ดังนั้นเราจึงยืมเมธอด slice
ซ์จาก Array.prototype
เพื่อช่วยเราแปลง arguments
เป็นอาเรย์จริง เพื่ออำนวยความสะดวกในการดำเนินงานที่ดีขึ้นcreateCurry
เป็นครั้งแรก ตัวแปร stored_args
จะเก็บพารามิเตอร์ไว้ยกเว้นพารามิเตอร์ตัวแรก เนื่องจากพารามิเตอร์แรกคือฟังก์ชันที่เราจำเป็นต้องแกงcreateCurry
ตัวแปร new_args
จะได้รับพารามิเตอร์และแปลงเป็นอาร์เรย์stored_args
ผ่านการปิดและรวมค่าของตัวแปร new_args
เข้ากับอาร์เรย์ใหม่และกำหนดให้กับตัวแปร args
fn.apply(null,args)
จะถูกเรียกเพื่อรันฟังก์ชัน curriedทีนี้มาทดสอบฟังก์ชันแกงสาธารณะ
// ฟังก์ชันธรรมดา add() ฟังก์ชั่นเพิ่ม(x, y){ กลับ x + y; - // Curry เพื่อรับฟังก์ชันใหม่ var newAdd = createCurry(add,4); console.log(เพิ่มใหม่(6)); // 10 //วิธีง่ายๆ อีกวิธีหนึ่ง console.log(createCurry(add,4)(6));// 10
แน่นอนว่านี่ไม่ได้จำกัดอยู่แค่การซ้อนพารามิเตอร์สองตัวเท่านั้น แต่ยังรวมถึงพารามิเตอร์หลายตัวด้วย:
// พารามิเตอร์หลายตัว ฟังก์ชันฟังก์ชันธรรมดาจะเพิ่ม (ก,ข,ค,ง){ กลับ + b + c + d; - // Curry ฟังก์ชั่นเพื่อรับฟังก์ชั่นใหม่ สามารถแบ่งพารามิเตอร์ได้หลายตัวที่ will console.log(createCurry(add,4,5)(5,6)); // 20 // แกงสองขั้นตอน ให้ add_one = createCurry(เพิ่ม,5); console.log(add_one(5,5,5));// 20 ให้ add_two = createCurry(add_one,4,6); console.log(add_two(6)); // 21จาก
ตัวอย่างข้างต้น เราสามารถค้นหาข้อจำกัดได้ กล่าวคือ ไม่ว่าจะเป็นพารามิเตอร์สองตัวหรือหลายพารามิเตอร์ ก็สามารถดำเนินการได้ในสองขั้นตอนเท่านั้น เช่น สูตรต่อไปนี้:
หากเราต้องการความยืดหยุ่นมากขึ้น:
;
หลังจากแบบฝึกหัดข้างต้น เราพบว่าฟังก์ชัน Curried ที่เราสร้างขึ้นมีข้อจำกัดบางประการ เราหวังว่าฟังก์ชันนี้จะสามารถทำงานได้หลายขั้นตอน:
// สร้างฟังก์ชัน Curried ที่สามารถดำเนินการได้หลายขั้นตอน Function ให้ดำเนินการเมื่อถึงจำนวนพารามิเตอร์: // สูตรฟังก์ชัน: fn(x,y,z,w) ==> fn(x)(y)(z)(w); ให้ createCurry = (fn,...params)=> { ให้ args = parsms ||. ให้ fnLen = fn.length; // ระบุความยาวพารามิเตอร์ของฟังก์ชัน curried กลับ (...ความละเอียด)=> { // รับพารามิเตอร์ก่อนหน้านี้ทั้งหมดผ่านห่วงโซ่ขอบเขต ให้ allArgs = args.slice(0); // คัดลอกพารามิเตอร์ args ที่ใช้ร่วมกันโดยการปิดเพื่อหลีกเลี่ยงผลกระทบของการดำเนินการที่ตามมา (ประเภทอ้างอิง) allArgs.push(...รายละเอียด); ถ้า (allArgs.length < fnLen){ // เมื่อจำนวนพารามิเตอร์น้อยกว่าความยาวพารามิเตอร์ของฟังก์ชันดั้งเดิม ให้เรียกใช้ฟังก์ชัน createCurry ซ้ำเพื่อส่งคืน createCurry.call(this,fn,...allArgs); }อื่น{ // เมื่อครบจำนวนพารามิเตอร์แล้ว การดำเนินการฟังก์ชันทริกเกอร์จะส่งคืน fn.apply(this,allArgs); - - - // ฟังก์ชันสามัญ เพิ่มฟังก์ชัน(a,b,c,d){ พร้อมพารามิเตอร์หลายตัว กลับ + b + c + d; - //ทดสอบฟังก์ชั่นการแกง ให้curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); //
เราได้ใช้ฟังก์ชันการแกงแบบยืดหยุ่นมานานกว่า 10 ปี แต่ที่นี่เราพบปัญหาอื่น:
curryAdd(add,1,2,3,4)()
;add()
ดั้งเดิม นี่เป็นวิธีหนึ่งเช่นกัน แต่เนื่องจากเราพอใจกับจำนวนพารามิเตอร์ที่นี่ เราจึงยังคงจัดการกับสถานการณ์นี้ที่นี่เราเพียงต้องตัดสินใจก่อนที่จะส่งคืนฟังก์ชัน:
ให้ createCurry = (fn,...params)=> { ให้ args = parsms ||. ให้ fnLen = fn.length; // ระบุความยาวพารามิเตอร์ของฟังก์ชัน curried ถ้า (ความยาว === _args.length) { //เพิ่มวิจารณญาณ หากจำนวนพารามิเตอร์ในครั้งแรกเพียงพอ ให้เรียกใช้ฟังก์ชันโดยตรงเพื่อรับผลลัพธ์ที่ส่งคืน fn.apply(this,args); - กลับ (...ความละเอียด)=> { ให้ allArgs = args.slice(0); allArgs.push(...รายละเอียด); ถ้า (allArgs.length < fnLen){ ส่งคืน createCurry.call (นี่, fn, ... allArgs); }อื่น{ กลับ fn.apply (นี่คือ allArgs); - }}
ข้างต้นถือได้ว่าเป็นฟังก์ชัน curried ที่ยืดหยุ่นได้ แต่ที่นี่ไม่ยืดหยุ่นมากนัก เนื่องจากเราไม่สามารถควบคุมได้ว่าเมื่อใดที่จะถูกดำเนินการ ตราบใดที่จำนวนพารามิเตอร์เพียงพอ ก็จะถูกดำเนินการโดยอัตโนมัติ เราควรทำอย่างไรหากเราต้องการบรรลุจังหวะเวลาที่สามารถควบคุมการดำเนินการได้?
ได้ ที่นี่:
// เมื่อพารามิเตอร์ครบแล้ว ให้เรียกใช้ฟังก์ชัน la createCurry = (fn,...params)=> { ให้ args = parsms ||. ให้ fnLen = fn.length; // ระบุความยาวพารามิเตอร์ของฟังก์ชัน curried //แน่นอนว่าจำเป็นต้องใส่ความคิดเห็นในการตัดสินที่นี่ ไม่เช่นนั้นผลลัพธ์จะถูกดำเนินการโดยตรงเมื่อจำนวนพารามิเตอร์เพียงพอในครั้งแรก //if(length === _args.length){ // เพิ่มการตัดสิน หากจำนวนพารามิเตอร์ในครั้งแรกเพียงพอ ให้เรียกใช้ฟังก์ชันโดยตรงเพื่อรับผลลัพธ์ //return fn.apply(this,args); - กลับ (...ความละเอียด)=> { ให้ allArgs = args.slice(0); allArgs.push(...รายละเอียด); // ที่นี่จะตัดสินว่าพารามิเตอร์อินพุตมากกว่า 0 หรือไม่ หากมากกว่า 0 จะตัดสินว่าจำนวนพารามิเตอร์เพียงพอหรือไม่ // && ไม่สามารถใช้ที่นี่ได้ หากใช้ && ผลลัพธ์จะถูกดำเนินการเมื่อจำนวนพารามิเตอร์เพียงพอ ถ้า (res.length > 0 || allArgs.length < fnLen){ ส่งคืน createCurry.call (นี่, fn, ... allArgs); }อื่น{ กลับ fn.apply (นี่คือ allArgs); - - - // ฟังก์ชันสามัญ เพิ่มฟังก์ชัน(a,b,c,d){ พร้อมพารามิเตอร์หลายตัว กลับ + b + c + d; - // ทดสอบฟังก์ชันการแกงที่ควบคุมได้ ให้curryAdd = createCurry(add,1); console.log(curryAdd(2)(3)(4)); // ฟังก์ชั่น console.log(curryAdd(2)(3)(4)()); // 10 console.log(curryAdd(2)(3)()); // ส่งคืน NaN เมื่อพารามิเตอร์ไม่เพียงพอ
: บทช่วยสอนการเรียนรู้ JavaScript
ข้างต้นคือการพูดคุยเกี่ยวกับรายละเอียดของฟังก์ชัน JavaScript โปรดใส่ใจกับบทความ php อื่น ๆ ที่เกี่ยวข้องบนเว็บไซต์จีน!