มีวิธีให้พารามิเตอร์ที่มีชื่อในการเรียกใช้ฟังก์ชันใน JavaScript หรือไม่


207

ฉันพบว่าคุณสมบัติพารามิเตอร์ที่มีชื่อใน C # ค่อนข้างมีประโยชน์ในบางกรณี

calculateBMI(70, height: 175);

ฉันจะใช้อะไรได้ถ้าฉันต้องการสิ่งนี้ใน JavaScript


สิ่งที่ฉันไม่ต้องการคือ:

myFunction({ param1: 70, param2: 175 });

function myFunction(params){
  // Check if params is an object
  // Check if the parameters I need are non-null
  // Blah blah
}

วิธีการที่ฉันใช้ไปแล้ว มีวิธีอื่นอีกไหม?

ฉันโอเคที่จะใช้ห้องสมุดเพื่อทำสิ่งนี้


ฉันไม่คิดว่ามันเป็นไปได้ แต่คุณสามารถลองใส่สิ่งที่ไม่ได้กำหนดไว้ในที่ว่างได้ ซึ่งเป็นวิธีที่ไม่ดี ใช้วัตถุมันดี
Vladislav Qulin

14
ไม่, JavaScript / EcmaScript ไม่รองรับพารามิเตอร์ที่มีชื่อ ขอโทษ
smilly92

1
ฉันรู้แล้วว่า ขอบคุณ ฉันกำลังมองหาวิธีที่เกี่ยวข้องกับการปรับแต่งสิ่งที่มีอยู่Functionในจาวาสคริปต์สามารถทำได้
Robin Maben

1
ที่มีอยู่Functionใน Javascript ไม่สามารถเปลี่ยนไวยากรณ์หลักของ Javascript ได้
Gareth

2
ฉันไม่คิดว่า Javascript รองรับคุณสมบัตินี้ ผมคิดว่าใกล้เคียงที่สุดที่คุณสามารถมาชื่อพารามิเตอร์คือ (1) เพิ่มความคิดเห็นcalculateBMI(70, /*height:*/ 175);(2) ให้วัตถุcalculateBMI(70, {height: 175})หรือ (3) const height = 175; calculateBMI(70, height);การใช้อย่างต่อเนื่อง
tfmontague

คำตอบ:


212

ES2015 และใหม่กว่า

ใน ES2015 การทำลายโครงสร้างพารามิเตอร์สามารถใช้เพื่อจำลองพารามิเตอร์ที่มีชื่อ มันจะต้องมีผู้โทรผ่านวัตถุ แต่คุณสามารถหลีกเลี่ยงการตรวจสอบทั้งหมดภายในฟังก์ชั่นถ้าคุณยังใช้พารามิเตอร์เริ่มต้น:

myFunction({ param1 : 70, param2 : 175});

function myFunction({param1, param2}={}){
  // ...function body...
}

// Or with defaults, 
function myFunc({
  name = 'Default user',
  age = 'N/A'
}={}) {
  // ...function body...
}

ES5

มีวิธีที่จะเข้าใกล้สิ่งที่คุณต้องการ แต่มันขึ้นอยู่กับเอาท์พุทของFunction.prototype.toString [ES5]ซึ่งเป็นการนำไปใช้งานขึ้นอยู่กับระดับดังนั้นมันอาจไม่เข้ากันข้ามเบราว์เซอร์

แนวคิดคือการแยกชื่อพารามิเตอร์จากการแสดงสตริงของฟังก์ชันเพื่อให้คุณสามารถเชื่อมโยงคุณสมบัติของวัตถุกับพารามิเตอร์ที่เกี่ยวข้อง

การเรียกใช้ฟังก์ชันอาจมีลักษณะเช่นนั้น

func(a, b, {someArg: ..., someOtherArg: ...});

โดยที่aและbเป็นอาร์กิวเมนต์ตำแหน่งและอาร์กิวเมนต์สุดท้ายเป็นวัตถุที่มีอาร์กิวเมนต์ที่มีชื่อ

ตัวอย่างเช่น:

var parameterfy = (function() {
    var pattern = /function[^(]*\(([^)]*)\)/;

    return function(func) {
        // fails horribly for parameterless functions ;)
        var args = func.toString().match(pattern)[1].split(/,\s*/);

        return function() {
            var named_params = arguments[arguments.length - 1];
            if (typeof named_params === 'object') {
                var params = [].slice.call(arguments, 0, -1);
                if (params.length < args.length) {
                    for (var i = params.length, l = args.length; i < l; i++) {
                        params.push(named_params[args[i]]);
                    }
                    return func.apply(this, params);
                }
            }
            return func.apply(null, arguments);
        };
    };
}());

ซึ่งคุณจะใช้เป็น:

var foo = parameterfy(function(a, b, c) {
    console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);     
});

foo(1, 2, 3); // a is 1  | b is 2  | c is 3
foo(1, {b:2, c:3}); // a is 1  | b is 2  | c is 3
foo(1, {c:3}); // a is 1  | b is undefined  | c is 3
foo({a: 1, c:3}); // a is 1  | b is undefined  | c is 3 

การสาธิต

มีข้อเสียบางอย่างสำหรับวิธีการนี้ (คุณได้รับคำเตือน!):

  • หากอาร์กิวเมนต์สุดท้ายเป็นวัตถุจะถือว่าเป็น "วัตถุอาร์กิวเมนต์ที่ระบุชื่อ"
  • คุณจะได้รับอาร์กิวเมนต์มากที่สุดเท่าที่คุณกำหนดไว้ในฟังก์ชัน แต่บางข้ออาจมีค่าundefined(ซึ่งแตกต่างจากการไม่มีค่าเลย) นั่นหมายความว่าคุณไม่สามารถใช้arguments.lengthเพื่อทดสอบว่ามีการส่งผ่านอาร์กิวเมนต์จำนวนเท่าใด

แทนที่จะมีฟังก์ชั่นในการสร้างเสื้อคลุมคุณสามารถมีฟังก์ชั่นที่รับฟังก์ชั่นและค่าต่าง ๆ เป็นอาร์กิวเมนต์เช่น

call(func, a, b, {posArg: ... });

หรือยืดออกFunction.prototypeเพื่อที่คุณจะได้ทำ:

foo.execute(a, b, {posArg: ...});

ใช่ ... นี่คือตัวอย่างสำหรับสิ่งนั้น: jsfiddle.net/9U328/1 (แม้ว่าคุณควรจะใช้Object.definePropertyและตั้งค่าenumerableเป็นfalse) หนึ่งควรระวังเมื่อขยายวัตถุพื้นเมือง วิธีการทั้งรู้สึก hacky บิตดังนั้นฉันจะไม่คาดหวังว่ามันจะทำงานในขณะนี้และตลอดไป)
เฟลิกซ์แพรว

ข้อสังเกต. ฉันจะลงเพื่อใช้สิ่งนี้ ทำเครื่องหมายว่าเป็นคำตอบ! ... สำหรับตอนนี้;)
Robin Maben

1
มาก nitpick ผู้เยาว์: ผมไม่คิดว่าวิธีการนี้จะจับ ECMAScript 6 ฟังก์ชั่นลูกศร ไม่ใช่เรื่องที่น่าเป็นห่วงในปัจจุบัน แต่อาจคุ้มค่าที่จะกล่าวถึงในส่วนคำเตือนของคำตอบของคุณ
NobodyMan

3
@NobodyMan: จริง ฉันเขียนคำตอบนี้ก่อนฟังก์ชั่นลูกศรเป็นสิ่งหนึ่ง ใน ES6 ฉันจะใช้วิธีการทำลายล้างพารามิเตอร์จริง ๆ
เฟลิกซ์คลิง

1
ในประเด็นของundefinedvs "no value" สามารถเพิ่มได้ว่านี่เป็นวิธีการที่ค่าเริ่มต้นของฟังก์ชั่นของ JS ทำงานอย่างแท้จริงโดยถือว่าundefinedเป็นค่าที่หายไป
Dmitri Zaitsev

71

ไม่ - วิธีการของวัตถุคือคำตอบของ JavaScript สำหรับสิ่งนี้ ไม่มีปัญหากับสิ่งนี้หากฟังก์ชั่นของคุณคาดว่าจะเป็นวัตถุแทนที่จะเป็นพารามิเตอร์แยกต่างหาก


35
@RobertMaben - คำตอบสำหรับคำถามเฉพาะที่ถามคือไม่มีวิธีดั้งเดิมในการรวบรวม vars หรือฟังก์ชั่นที่ประกาศไว้โดยไม่ทราบว่าอยู่ในเนมสเปซที่เจาะจง เพียงเพราะคำตอบสั้นมันไม่ได้เป็นการลบล้างความเหมาะสมในฐานะคำตอบ - คุณจะไม่เห็นด้วยหรือ มีคำตอบที่สั้นกว่านั้นมากตามแนวของ "ไม่ไม่เป็นไปได้" พวกเขาอาจสั้น แต่ก็เป็นคำตอบสำหรับคำถามด้วย
Mitya

3
ทุกวันนี้มี es6 อยู่: 2ality.com/2011/11/keyword-parameters.html
slacktracer

1
นี่เป็นคำตอบที่ยุติธรรม - 'พารามิเตอร์ที่ตั้งชื่อ' เป็นคุณสมบัติภาษา วิธีการใช้วัตถุเป็นสิ่งที่ดีที่สุดถัดไปหากไม่มีคุณสมบัติดังกล่าว
fatuhoku

32

ปัญหานี้ได้กลายเป็นสัตว์เลี้ยงที่โกรธแค้นของฉันมาระยะหนึ่งแล้ว ฉันเป็นโปรแกรมเมอร์ที่มีประสบการณ์หลายภาษาภายใต้การดูแลของฉัน หนึ่งในภาษาที่ฉันชอบที่ฉันมีความยินดีที่จะใช้คือ Python Python สนับสนุนพารามิเตอร์ที่กำหนดชื่อโดยไม่มีการใช้เล่ห์อุบายใด ๆ .... ตั้งแต่ฉันเริ่มใช้ Python (บางเวลาที่ผ่านมา) ทุกอย่างกลายเป็นง่ายขึ้น ฉันเชื่อว่าทุกภาษาควรสนับสนุนพารามิเตอร์ที่มีชื่อ แต่นั่นไม่ใช่กรณี

ผู้คนจำนวนมากพูดเพียงแค่ใช้เคล็ดลับ "ส่งต่อวัตถุ" เพื่อให้คุณได้ตั้งชื่อพารามิเตอร์

/**
 * My Function
 *
 * @param {Object} arg1 Named arguments
 */
function myFunc(arg1) { }

myFunc({ param1 : 70, param2 : 175});

และมันใช้งานได้ดียกเว้น ..... เมื่อพูดถึง IDEs ส่วนใหญ่แล้วนักพัฒนาของเราจำนวนมากพึ่งพาคำแนะนำประเภท / อาร์กิวเมนต์ภายใน IDE ของเรา ฉันใช้ PHP Storm เป็นการส่วนตัว (พร้อมกับ JetBrains IDEs อื่น ๆ เช่น PyCharm สำหรับ python และ AppCode สำหรับ Objective C)

และปัญหาที่ใหญ่ที่สุดในการใช้เคล็ดลับ "ส่งผ่านวัตถุ" คือเมื่อคุณเรียกใช้ฟังก์ชัน IDE จะให้คำแนะนำประเภทเดียวและนั่นคือ ... เราจะทราบได้อย่างไรว่าพารามิเตอร์และประเภทใดควรเข้าสู่ วัตถุ arg1?

ฉันไม่ทราบว่าควรใช้พารามิเตอร์ใดใน arg1

ดังนั้น ... เคล็ดลับ "ส่งต่อวัตถุ" ไม่เหมาะกับฉัน ... มันทำให้เกิดอาการปวดหัวมากขึ้นโดยไม่ต้องดูที่ docblock ของแต่ละฟังก์ชั่นก่อนที่ฉันจะรู้ว่าฟังก์ชันคาดหวังว่าพารามิเตอร์ใด เมื่อคุณรักษารหัสที่มีอยู่ แต่มันน่ากลัวสำหรับการเขียนรหัสใหม่

นี่เป็นเทคนิคที่ฉันใช้ .... ตอนนี้อาจมีปัญหาบางอย่างกับมันและนักพัฒนาบางคนอาจบอกฉันว่าฉันทำผิดและฉันมีใจที่เปิดกว้างเมื่อพูดถึงสิ่งเหล่านี้ ... ฉันยินดีที่จะมองหาวิธีที่ดีกว่าในการทำงานให้สำเร็จ ... ดังนั้นหากมีปัญหากับเทคนิคนี้ความคิดเห็นก็ยินดีต้อนรับ

/**
 * My Function
 *
 * @param {string} arg1 Argument 1
 * @param {string} arg2 Argument 2
 */
function myFunc(arg1, arg2) { }

var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');

ด้วยวิธีนี้ฉันมีสิ่งที่ดีที่สุดของทั้งสองโลก ... รหัสใหม่ง่ายต่อการเขียนเนื่องจาก IDE ของฉันให้คำแนะนำอาร์กิวเมนต์ที่เหมาะสมทั้งหมดแก่ฉัน ... และในขณะที่รักษารหัสไว้ในภายหลังฉันสามารถเห็นได้ทันทีไม่เพียง ค่าที่ส่งผ่านไปยังฟังก์ชั่น แต่ยังชื่อของอาร์กิวเมนต์ ค่าใช้จ่ายเพียงอย่างเดียวที่ฉันเห็นคือการประกาศชื่ออาร์กิวเมนต์ของคุณเป็นตัวแปรท้องถิ่นเพื่อไม่ให้เกิดมลภาวะต่อเนมสเปซส่วนกลาง แน่นอนว่ามันเป็นงานพิมพ์ที่พิเศษ แต่เล็กน้อยเมื่อเทียบกับเวลาที่ใช้ในการค้นหา docblock ในขณะที่เขียนรหัสใหม่หรือรักษารหัสที่มีอยู่

ตอนนี้ฉันมีพารามิเตอร์และประเภททั้งหมดเมื่อสร้างรหัสใหม่


2
สิ่งเดียวที่ใช้เทคนิคนี้คือความจริงที่ว่าคุณไม่สามารถเปลี่ยนลำดับของพารามิเตอร์ได้ ...
Ray Perea

13
ดูเหมือนว่านี่เป็นเพียงการถามถึงปัญหาเมื่อผู้ดูแลในอนาคตบางคนเข้ามาและคิดว่าพวกเขาสามารถเปลี่ยนคำสั่งโต้แย้ง (แต่เห็นได้ชัดว่าไม่ได้)
ไม่มีใคร

1
@AndrewMedico ฉันเห็นด้วย ... มันดูเหมือนว่าคุณสามารถเปลี่ยนลำดับอาร์กิวเมนต์เช่นเดียวกับใน Python สิ่งเดียวที่ฉันสามารถพูดเกี่ยวกับที่พวกเขาจะหาจริงอย่างรวดเร็วเมื่อเปลี่ยนลำดับการโต้แย้งแบ่งโปรแกรม
Ray Perea

7
ฉันจะเถียงว่าmyFunc(/*arg1*/ 'Param1', /*arg2*/ 'Param2');ดีกว่าmyFunc(arg1='Param1', arg2='Param2');เพราะไม่มีโอกาสหลอกผู้อ่านมากกว่าข้อโต้แย้งที่มีชื่อจริงใด ๆ ที่เกิดขึ้น
Eric

2
รูปแบบที่เสนอนั้นไม่มีส่วนเกี่ยวข้องกับอาร์กิวเมนต์ที่มีชื่อลำดับยังคงมีความสำคัญชื่อไม่จำเป็นต้องซิงค์กับพารามิเตอร์จริงเนมสเปซจะถูกปนเปื้อนด้วยตัวแปรที่ไม่จำเป็นและความสัมพันธ์นั้นไม่ได้ระบุไว้
Dmitri Zaitsev

25

หากคุณต้องการให้ชัดเจนว่าแต่ละพารามิเตอร์คืออะไรแทนที่จะแค่เรียก

someFunction(70, 115);

ทำไมไม่ทำต่อไปนี้

var width = 70, height = 115;
someFunction(width, height);

แน่นอนว่ามันเป็นรหัสพิเศษ แต่สามารถอ่านได้


5
+1 สำหรับการติดตามหลักการ KISS รวมถึงช่วยแก้ไขข้อบกพร่องได้เช่นกัน อย่างไรก็ตามฉันคิดว่าแต่ละ var ควรอยู่ในบรรทัดของตัวเองแม้ว่าจะมีประสิทธิภาพการทำงานเล็กน้อย ( http://stackoverflow.com/questions/9672635/javascript-var-statement-and-performance )
clairestreb

21
มันไม่เพียงเกี่ยวกับบรรทัดของรหัสพิเศษเท่านั้น แต่ยังเกี่ยวกับลำดับของอาร์กิวเมนต์และทำให้เป็นทางเลือก ดังนั้นคุณสามารถเขียนสิ่งนี้ด้วยพารามิเตอร์ที่มีชื่อ: someFunction(height: 115);แต่ถ้าคุณเขียนsomeFunction(height);คุณกำลังตั้งค่าความกว้าง
Francisco Presencia

ในกรณีนั้น CoffeeScript สนับสนุนอาร์กิวเมนต์ที่มีชื่อ someFunction(width = 70, height = 115);มันจะช่วยให้คุณเขียนเพียง ตัวแปรจะถูกประกาศที่ด้านบนของขอบเขตปัจจุบันในรหัส JavaScript ซึ่งสร้างขึ้น
Audun Olsen

6

อีกวิธีหนึ่งคือการใช้คุณสมบัติของวัตถุที่เหมาะสมเช่นเช่น:

function plus(a,b) { return a+b; };

Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}}, 
         b: function(y) { return { a: function(x) { return plus(x,y) }}}};

sum = Plus.a(3).b(5);

แน่นอนสำหรับตัวอย่างนี้มันค่อนข้างไร้ความหมาย แต่ในกรณีที่ฟังก์ชั่นมีหน้าตาเป็นอย่างไร

do_something(some_connection_handle, some_context_parameter, some_value)

มันอาจมีประโยชน์มากกว่า นอกจากนี้ยังสามารถใช้ร่วมกับแนวคิด "parameterfy" เพื่อสร้างวัตถุดังกล่าวจากฟังก์ชันที่มีอยู่ในวิธีทั่วไป นั่นคือสำหรับแต่ละพารามิเตอร์มันจะสร้างสมาชิกที่สามารถประเมินเป็นฟังก์ชันการประเมินรุ่นบางส่วน

ความคิดนี้แน่นอนว่าเกี่ยวข้องกับSchönfinkeling aka Currying


นี่เป็นความคิดที่เนี้ยบและจะดียิ่งขึ้นถ้าคุณรวมเข้ากับเล่ห์เหลี่ยมการโต้เถียง น่าเสียดายที่มันไม่เพียงพอสำหรับการใช้อาร์กิวเมนต์ที่มีตัวเลือก
Eric

2

มีวิธีอื่น หากคุณกำลังส่งวัตถุโดยการอ้างอิงคุณสมบัติของวัตถุนั้นจะปรากฏในขอบเขตภายในของฟังก์ชัน ฉันรู้ว่าใช้งานได้กับ Safari (ยังไม่ได้ตรวจสอบเบราว์เซอร์อื่น) และฉันไม่รู้ว่าคุณลักษณะนี้มีชื่อหรือไม่ แต่ตัวอย่างด้านล่างแสดงให้เห็นถึงการใช้งาน

แม้ว่าในทางปฏิบัติฉันไม่คิดว่าสิ่งนี้จะมอบคุณค่าการทำงานใด ๆ ที่เกินกว่าเทคนิคที่คุณใช้อยู่ แต่ก็สะอาดกว่าความหมายเล็กน้อย และมันยังต้องผ่านการอ้างอิงวัตถุหรือวัตถุตามตัวอักษร

function sum({ a:a, b:b}) {
    console.log(a+'+'+b);
    if(a==undefined) a=0;
    if(b==undefined) b=0;
    return (a+b);
}

// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));

// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));

2

ลองใช้ Node-6.4.0 (process.versions.v8 = '5.0.71.60') และ Node Chakracore-v7.0.0-pre8 แล้ว Chrome-52 (V8 = 5.2.361.49) ฉันสังเกตว่าพารามิเตอร์ที่ตั้งชื่อนั้นเกือบจะแล้วดำเนินการแล้ว แต่คำสั่งนั้นยังคงมีความสำคัญกว่า ฉันไม่พบสิ่งที่มาตรฐาน ECMA พูด

>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }

> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17

แต่ต้องสั่งซื้อ !! มันเป็นพฤติกรรมมาตรฐานหรือไม่?

> f(b=10)
a=10 + b=2 = 12

10
นั่นไม่ใช่สิ่งที่คุณคิด ผลลัพธ์ของb=10นิพจน์คือ10และนั่นคือสิ่งที่ส่งผ่านไปยังฟังก์ชัน f(bla=10)จะใช้งานได้ (มันกำหนด 10 ให้กับตัวแปรblaและส่งผ่านค่าไปยังฟังก์ชันหลังจากนั้น)
Matthias Kestenholz

1
นี่คือการสร้างaและbตัวแปรในขอบเขตส่วนกลางเป็นผลข้างเคียง
Gershom

2

ฟังก์ชั่นการโทรfด้วยพารามิเตอร์ที่ตั้งชื่อส่งผ่านเป็นวัตถุ

o = {height: 1, width: 5, ...}

เป็นพื้นเรียกองค์ประกอบของf(...g(o))ที่ฉันใช้ไวยากรณ์การแพร่กระจายและgเป็นแผนที่ "ผูกพัน" เชื่อมต่อค่าวัตถุที่มีตำแหน่งพารามิเตอร์ของพวกเขา

แผนผังการโยงเป็นส่วนประกอบที่ขาดหายไปอย่างแม่นยำซึ่งสามารถแสดงได้ด้วยอาร์เรย์ของคีย์:

// map 'height' to the first and 'width' to the second param
binding = ['height', 'width']

// take binding and arg object and return aray of args
withNamed = (bnd, o) => bnd.map(param => o[param])

// call f with named args via binding
f(...withNamed(binding, {hight: 1, width: 5}))

สังเกตส่วนผสมที่แยกออกได้สามอย่าง:ฟังก์ชันวัตถุที่มีอาร์กิวเมนต์ที่มีชื่อและการเชื่อมโยง การแยก decoupling นี้ช่วยให้มีความยืดหยุ่นมากในการใช้โครงสร้างนี้ซึ่งการผูกสามารถกำหนดเองโดยพลการในนิยามของฟังก์ชันและขยายโดยพลการในเวลาเรียกฟังก์ชัน

ตัวอย่างเช่นคุณอาจต้องการย่อheightและwidthตามhและwภายในนิยามฟังก์ชันของคุณเพื่อทำให้สั้นลงและสะอาดขึ้นในขณะที่คุณยังคงต้องการเรียกมันด้วยชื่อเต็มเพื่อความชัดเจน:

// use short params
f = (h, w) => ...

// modify f to be called with named args
ff = o => f(...withNamed(['height', 'width'], o))

// now call with real more descriptive names
ff({height: 1, width: 5})

ความยืดหยุ่นนี้ยังมีประโยชน์มากขึ้นสำหรับการตั้งโปรแกรมการใช้งานซึ่งฟังก์ชั่นสามารถเปลี่ยนได้โดยพลการด้วยชื่อพารามิเตอร์ดั้งเดิมที่หายไป


0

มาจาก Python ทำให้ฉันรู้สึกแย่ ฉันเขียน wrapper / Proxy อย่างง่ายสำหรับโหนดที่จะยอมรับทั้งตำแหน่งและวัตถุคำหลัก

https://github.com/vinces1979/node-def/blob/master/README.md


หากฉันเข้าใจถูกต้องโซลูชันของคุณต้องแยกแยะตำแหน่งและพารามิเตอร์ที่มีชื่อในคำจำกัดความของฟังก์ชั่นซึ่งหมายความว่าฉันไม่มีอิสระที่จะเลือกตัวเลือกนี้ในเวลาที่โทร
Dmitri Zaitsev

@DmitriZaitsev: ในชุมชน Python (ที่มีอาร์กิวเมนต์ของคำหลักเป็นคุณลักษณะประจำวัน) เราคิดว่าเป็นความคิดที่ดีมากที่จะสามารถบังคับให้ผู้ใช้ระบุอาร์กิวเมนต์ที่เป็นตัวเลือกด้วยคีย์เวิร์ด; สิ่งนี้ช่วยในการหลีกเลี่ยงข้อผิดพลาด
โทเบียส

@Tobias การบังคับให้ผู้ใช้ทำเช่นนั้นใน JS เป็นปัญหาที่แก้ไขแล้ว: f(x, opt)ที่ไหนoptคือวัตถุ ไม่ว่าจะช่วยหลีกเลี่ยงหรือสร้างข้อผิดพลาด (เช่นเกิดจากการสะกดผิดและความเจ็บปวดในการจำชื่อคำหลัก) ยังคงเป็นคำถาม
Dmitri Zaitsev

@DmitriZaitsev: ใน Python นี่เป็นการหลีกเลี่ยงข้อผิดพลาดอย่างเคร่งครัดเนื่องจาก (แน่นอน) อาร์กิวเมนต์ของคำหลักเป็นคุณลักษณะภาษาหลักที่นั่น สำหรับอาร์กิวเมนต์คำหลักเท่านั้น Python 3 มีไวยากรณ์พิเศษ (ใน Python 2 คุณจะป๊อปอัพคีย์จากkwargs dictทีละหนึ่งและในที่สุดก็เพิ่มTypeErrorคีย์หากไม่ทราบคีย์ที่เหลืออยู่) คุณf(x, opt)แก้ปัญหาช่วยให้fฟังก์ชั่นที่จะทำสิ่งที่ชอบในหลาม 2 แต่คุณจะต้องจัดการกับค่าเริ่มต้นเองทั้งหมด
โทเบียส

@Tobias ข้อเสนอนี้เกี่ยวข้องกับ JS หรือไม่ ดูเหมือนว่าจะอธิบายวิธีการf(x, opt)ทำงานอยู่แล้วในขณะที่ฉันไม่เห็นวิธีการนี้จะช่วยตอบคำถามที่คุณต้องการทำทั้งสองอย่างrequest(url)และrequest({url: url})ไม่สามารถทำได้โดยการurlใช้พารามิเตอร์คำหลักเท่านั้น
Dmitri Zaitsev

-1

ตรงกันข้ามกับสิ่งที่เชื่อกันโดยทั่วไปพารามิเตอร์ที่มีชื่อสามารถนำไปใช้ในมาตรฐานจาวาสคริปต์โรงเรียนเก่า (สำหรับพารามิเตอร์บูลีนเท่านั้น) โดยใช้วิธีการเข้ารหัสที่เรียบง่ายและเรียบร้อยดังที่แสดงด้านล่าง

function f(p1=true, p2=false) {
    ...
}

f(!!"p1"==false, !!"p2"==true); // call f(p1=false, p2=true)

คำเตือน:

  • การเรียงลำดับของอาร์กิวเมนต์ต้องได้รับการเก็บรักษาไว้ - แต่รูปแบบยังคงมีประโยชน์เนื่องจากมันทำให้เห็นได้ชัดว่าอาร์กิวเมนต์ที่แท้จริงนั้นมีความหมายสำหรับพารามิเตอร์ทางการใด ๆ โดยไม่ต้อง grep สำหรับฟังก์ชันลายเซ็นหรือใช้ IDE

  • ใช้งานได้กับ booleans เท่านั้น อย่างไรก็ตามฉันแน่ใจว่ารูปแบบที่คล้ายกันนี้สามารถพัฒนาสำหรับประเภทอื่น ๆ ได้โดยใช้ความหมายประเภทบังคับเฉพาะของ JavaScript


คุณยังอ้างอิงโดยตำแหน่งไม่ใช่ชื่อที่นี่
Dmitri Zaitsev

@DmitriZaitsev ใช่ฉันยังพูดอย่างนั้น อย่างไรก็ตามวัตถุประสงค์ของการโต้เถียงที่มีชื่อคือการทำให้ชัดเจนต่อผู้อ่านความหมายของแต่ละข้อโต้แย้ง; มันเป็นรูปแบบของเอกสาร โซลูชันของฉันช่วยให้สามารถฝังเอกสารภายในการเรียกใช้ฟังก์ชันโดยไม่หันไปใช้ความคิดเห็นซึ่งดูไม่เรียบร้อย
user234461

วิธีนี้จะช่วยแก้ปัญหาที่แตกต่าง คำถามคือเกี่ยวกับการผ่านheightชื่อโดยไม่คำนึงถึงคำสั่งของพารามิเตอร์
Dmitri Zaitsev

@DmitriZaitsev จริง ๆ แล้วคำถามไม่ได้พูดอะไรเกี่ยวกับการสั่งซื้อพารามิเตอร์หรือเหตุใด OP ต้องการใช้ชื่อ params
user234461

มันทำโดยอ้างถึง C # ที่ผ่าน params โดยชื่อในลำดับใด ๆ เป็นกุญแจสำคัญ
Dmitri Zaitsev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.