ต้นกำเนิดแกงกะหรี่และชื่อของนักคณิตศาสตร์ Haskell Curry (ภาษาการเขียนโปรแกรม Haskell ได้รับการตั้งชื่อตามเขาด้วย)
การแกงกะหรี่มักเรียกว่าการประเมินบางส่วน ความหมายของมันคือการส่งผ่านพารามิเตอร์ไปยังฟังก์ชันทีละขั้นตอน หลังจากผ่านพารามิเตอร์แต่ละตัวแล้วให้ใช้พารามิเตอร์บางส่วนและส่งคืนฟังก์ชันที่เฉพาะเจาะจงมากขึ้นเพื่อยอมรับพารามิเตอร์ที่เหลือ ฟังก์ชันพารามิเตอร์บางส่วนหลายชั้นสามารถซ้อนกันตรงกลางจนกว่าผลลัพธ์สุดท้ายจะถูกส่งคืน
ดังนั้นกระบวนการของการแกงเป็นกระบวนการของการผ่านพารามิเตอร์ค่อยๆค่อยๆลดขอบเขตของการใช้งานฟังก์ชั่นและค่อยๆแก้ปัญหา
แกงกะหรี่ฟังก์ชั่นผลรวม
ต่อไปนี้การประเมินทีละขั้นตอนลองดูตัวอย่างง่ายๆ
var concat3words = function (a, b, c) {return a+b+c; - var concat3wordscurrying = function (a) {return function (b) {return function (c) {return a+b+c; - - - console.log (concat3words ("foo", "bar", "baza")); // foo bar baza console.log (concat3wordscurrying ("foo")); // [ฟังก์ชั่น] console.log (concat3wordscurrying ("foo") ("bar") ("baza")); // foo bar bazaอย่างที่คุณเห็น concat3wordscurrying ("foo") เป็นฟังก์ชันการโทรแต่ละครั้งจะส่งคืนฟังก์ชันใหม่ซึ่งรับสายอื่นแล้วส่งคืนฟังก์ชั่นใหม่จนกว่าผลลัพธ์จะถูกส่งคืนในที่สุด (PS: ลักษณะของการปิดถูกนำมาใช้ประโยชน์ที่นี่)
ตอนนี้เราไปไกลกว่านี้ หากเราต้องการพารามิเตอร์มากกว่า 3 พารามิเตอร์เราสามารถส่งพารามิเตอร์ให้ได้มากที่สุดเท่าที่จะเป็นไปได้และส่งออกผลลัพธ์เมื่อพารามิเตอร์ไม่ผ่าน?
ก่อนอื่นให้มีการใช้งานปกติ:
var add = function (รายการ) {return items.Reduce (ฟังก์ชั่น (a, b) {return a+b}); - console.log (เพิ่ม ([1,2,3,4]));แต่ถ้าคุณขอคูณแต่ละหมายเลขด้วย 10 แล้วเพิ่มมันแล้ว:
var add = function (items, multi) {return items.map (ฟังก์ชั่น (รายการ) {return item*multi;}) ลด (ฟังก์ชั่น (a, b) {return a + b}); - console.log (เพิ่ม ([1, 2, 3, 4], 10));โชคดีที่มีแผนที่และลดฟังก์ชั่น หากเราทำตามรูปแบบนี้เราต้องเพิ่ม 1 ในแต่ละรายการและสรุปเราต้องแทนที่ฟังก์ชั่นในแผนที่
มาดูการใช้งาน curryization:
var adder = function () {var _args = []; return function () {if (arguments.length === 0) {return _args.reduce (ฟังก์ชั่น (a, b) {return a + b;}); } [] .push.apply (_args, [] .slice.call (อาร์กิวเมนต์)); คืนอาร์กิวเมนต์ Callee; - var sum = adder (); console.log (ผลรวม); // ฟังก์ชั่นผลรวม (100,200) (300); // รูปแบบการโทรมีความยืดหยุ่นพารามิเตอร์หนึ่งตัวขึ้นไปสามารถป้อนได้ครั้งละครั้งและรองรับการโทรแบบโซ่เป็นผลรวม (400); console.log (sum ()); // 1,000 (การคำนวณทั้งหมด)Adder ด้านบนเป็นฟังก์ชั่นรูปแกงกะหรี่ซึ่งส่งคืนฟังก์ชั่นใหม่และฟังก์ชั่นใหม่สามารถยอมรับพารามิเตอร์ใหม่ในแบทช์ล่าช้าจนกว่าการคำนวณครั้งสุดท้าย
ฟังก์ชั่นแกงทั่วไป
การแกงกะหรี่ทั่วไปจะห่อหุ้มการคำนวณครั้งสุดท้ายลงในฟังก์ชั่นจากนั้นส่งผ่านฟังก์ชั่นนี้เป็นพารามิเตอร์ลงในฟังก์ชันแกงกะหรี่ซึ่งชัดเจนและยืดหยุ่น
ตัวอย่างเช่นคูณแต่ละคำด้วย 10 เราสามารถผ่านฟังก์ชั่นการประมวลผลเป็นพารามิเตอร์:
var currying = function (fn) {var _args = []; return function () {if (arguments.length === 0) {return fn.apply (this, _args); } array.prototype.push.apply (_args, [] .slice.call (อาร์กิวเมนต์)); คืนอาร์กิวเมนต์ Callee; - var multi = function () {var total = 0; สำหรับ (var i = 0, c; c = อาร์กิวเมนต์ [i ++];) {total+= c; } ผลตอบแทนทั้งหมด; - var sum = currying (multi); ผลรวม (100,200) (300); ผลรวม (400); console.log (sum ()); // 1000 (คำนวณเฉพาะเมื่อมีการโทรว่าง)ด้วยวิธีนี้ sum = currying (multi) การโทรมีความชัดเจนมากและเอฟเฟกต์การใช้ก็ยอดเยี่ยมเช่นกัน ตัวอย่างเช่นในการสะสมหลายค่าคุณสามารถใช้หลายค่าเป็นผลรวมพารามิเตอร์ (1,2,3) หรือการเรียกสายโซ่สนับสนุนผลรวม (1) (2) (3)
รากฐานของการแกงกะหรี่
รหัสข้างต้นเป็นฟังก์ชั่นลำดับสูง ฟังก์ชั่นการสั่งซื้อสูงหมายถึงฟังก์ชั่นที่ทำงานฟังก์ชั่น ได้รับฟังก์ชั่นหนึ่งฟังก์ชั่นหรือมากกว่าเป็นพารามิเตอร์และส่งคืนฟังก์ชั่นใหม่ นอกจากนี้ลักษณะของการปิดยังต้องพึ่งพาเพื่อบันทึกพารามิเตอร์ที่ป้อนในกระบวนการระดับกลาง ตอนนี้:
ฟังก์ชั่นสามารถส่งผ่านเป็นพารามิเตอร์
ฟังก์ชั่นสามารถใช้เป็นค่าส่งคืนของฟังก์ชั่น
การปิด
บทบาทของการรักษา
การคำนวณล่าช้า ตัวอย่างข้างต้นค่อนข้างต่ำ
พารามิเตอร์มัลติเพล็กซ์ เมื่อฟังก์ชั่นเดียวกันนี้เรียกว่าหลายครั้งและพารามิเตอร์ที่ส่งผ่านส่วนใหญ่จะเหมือนกันฟังก์ชั่นอาจเป็นตัวเลือกที่ดีสำหรับการแกงกะหรี่
สร้างฟังก์ชั่นแบบไดนามิก สิ่งนี้สามารถสร้างขึ้นได้แบบไดนามิกหลังจากผลการคำนวณบางส่วนบนพื้นฐานนี้ฟังก์ชั่นใหม่จะถูกสร้างขึ้นแบบไดนามิกเพื่อประมวลผลธุรกิจที่ตามมาดังนั้นจึงไม่ต้องคำนวณซ้ำ หรือคุณสามารถสร้างฟังก์ชั่นใหม่แบบไดนามิกโดยการใช้ส่วนหนึ่งของชุดย่อยของพารามิเตอร์ที่จะส่งผ่านไปยังฟังก์ชั่นการโทรซึ่งจะช่วยประหยัดพารามิเตอร์ที่ผ่านซ้ำ ๆ (ไม่จำเป็นทุกครั้งในอนาคต) ตัวอย่างเช่นวิธีเสริมสำหรับเบราว์เซอร์กิจกรรมเพื่อเพิ่มเหตุการณ์:
var addevent = function (el, type, fn, capture) {ถ้า (window.addeVentListener) {el.addeventListener (ประเภท, ฟังก์ชัน (e) {fn.call (el, e);}, จับ); } อื่นถ้า (window.attachevent) {el.attachevent ("on" + type, function (e) {fn.call (el, e);}); -ทุกครั้งที่คุณเพิ่มเหตุการณ์คุณต้องดำเนินการถ้า ... อื่น .... อันที่จริงในเบราว์เซอร์คุณจะต้องตัดสินใจเพียงครั้งเดียว คุณสามารถสร้างฟังก์ชั่นใหม่ตามผลลัพธ์หลังจากการตัดสินและไม่จำเป็นต้องคำนวณใหม่ในอนาคต
var addevent = (function () {if (window.addeventListener) {ฟังก์ชั่น return (el, stype, fn, capture) {el.addeventListener (stype, function (e) {fn.call (el, e); El.AttacheVent ("on" + stype, function (e) {fn.call (el, e);});ตัวอย่างนี้หลังจากการตัดสินครั้งแรกของถ้า ... อื่น ... ส่วนหนึ่งของการคำนวณเสร็จสิ้นและฟังก์ชั่นใหม่ถูกสร้างขึ้นแบบไดนามิกเพื่อประมวลผลพารามิเตอร์ที่ส่งผ่านในภายหลัง นี่คือเคอร์รี่ทั่วไป
วิธีการ prototype.bind เป็นแอปพลิเคชันแกงกะหรี่
ซึ่งแตกต่างจากวิธีการโทร/ใช้ที่ดำเนินการโดยตรงวิธีการผูกตั้งค่าพารามิเตอร์แรกเป็นบริบทของการดำเนินการฟังก์ชั่นและพารามิเตอร์อื่น ๆ จะถูกส่งผ่านไปยังวิธีการโทรในทางกลับกัน (ร่างกายของฟังก์ชั่นเองไม่ได้ดำเนินการซึ่งถือได้ว่าเป็นการดำเนินการล่าช้า) และสร้างและส่งคืนฟังก์ชั่นใหม่
var foo = {x: 888}; var bar = function () {console.log (this.x); }. -bind (foo); // bind bar (); // 888ด้านล่างคือการจำลองฟังก์ชั่นการผูก TestBind สร้างและส่งคืนฟังก์ชั่นใหม่ ในฟังก์ชั่นใหม่ฟังก์ชั่นที่ต้องการดำเนินการธุรกิจนั้นถูกผูกไว้กับบริบทที่ส่งผ่านในพารามิเตอร์จริงและการดำเนินการล่าช้า
function.prototype.testbind = ฟังก์ชั่น (ขอบเขต) {var fn = this; //// นี้ชี้ไปที่ฟังก์ชั่นที่เรียกใช้วิธีการทดสอบ, ฟังก์ชัน return () {return fn.apply (ขอบเขต); - var testbindbar = bar.testbind (foo); // bind foo เพื่อชะลอการดำเนินการของ console.log (testbindbar); // ฟังก์ชั่น (ดูหลังจากผูกให้ส่งคืนฟังก์ชั่นใหม่ที่ทำให้การดำเนินการล่าช้า) TestBindBar (); // 888ที่นี่เราควรให้ความสนใจกับความเข้าใจในเรื่องนี้ในต้นแบบ
บทความข้างต้นการวิเคราะห์เชิงลึกของฟังก์ชั่นการแกว่งใน JavaScript Currying เป็นเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่าคุณจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น