มีวิธีการอนุญาต vars "ไม่ จำกัด " สำหรับฟังก์ชั่นใน JavaScript หรือไม่?
ตัวอย่าง:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
มีวิธีการอนุญาต vars "ไม่ จำกัด " สำหรับฟังก์ชั่นใน JavaScript หรือไม่?
ตัวอย่าง:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
คำตอบ:
แน่นอนว่าใช้arguments
วัตถุ
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
arguments
เป็นวัตถุพิเศษ "คล้ายอาร์เรย์" ซึ่งหมายความว่ามันมีความยาว แต่ไม่มีฟังก์ชันอาร์เรย์อื่น ๆ ดูdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/ …สำหรับข้อมูลเพิ่มเติมและคำตอบนี้: stackoverflow.com/a/13145228/1766230
length
คุณสมบัติ รวมถึงarguments
วัตถุด้วย รู้อย่างนี้แล้วและว่าวิธีการที่concat
จะส่งคืนสำเนาของ 'อาเรย์' ก็เรียกว่าอยู่กับเราได้อย่างง่ายดายสามารถแปลงวัตถุอาร์เรย์จริงเช่นนี้arguments
var args = [].concat.call(arguments)
บางคนชอบที่จะใช้Array.prototype.concat.call
แทน แต่ฉันชอบ[]
มันสั้นและหวาน!
[...arguments].join()
ในเบราว์เซอร์ล่าสุด (ส่วนใหญ่) คุณสามารถยอมรับจำนวนตัวแปรที่มีอาร์กิวเมนต์ด้วยไวยากรณ์นี้:
function my_log(...args) {
// args is an Array
console.log(args);
// You can pass this array as parameters to another function
console.log(...args);
}
นี่คือตัวอย่างเล็ก ๆ :
function foo(x, ...args) {
console.log(x, args, ...args, arguments);
}
foo('a', 'b', 'c', z='d')
=>
a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
0: "a"
1: "b"
2: "c"
3: "d"
length: 4
เอกสารและตัวอย่างเพิ่มเติมได้ที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
อีกทางเลือกหนึ่งคือการส่งผ่านข้อโต้แย้งของคุณในวัตถุบริบท
function load(context)
{
// do whatever with context.name, context.address, etc
}
และใช้มันแบบนี้
load({name:'Ken',address:'secret',unused:true})
นี่เป็นข้อดีที่คุณสามารถเพิ่มอาร์กิวเมนต์ที่มีชื่อมากเท่าที่คุณต้องการและฟังก์ชั่นสามารถใช้พวกเขา (หรือไม่) ตามที่เห็นสมควร
context
อาร์กิวเมนต์ด้วยรหัสและส่งผ่านมันก่อนที่มันจะถูกใช้
ฉันเห็นด้วยกับคำตอบของเคนว่าเป็นคนที่มีพลวัตมากที่สุดและฉันชอบที่จะก้าวไปอีกขั้น ถ้ามันเป็นฟังก์ชั่นที่คุณโทรหาหลายครั้งด้วยข้อโต้แย้งที่แตกต่างกัน - ฉันใช้การออกแบบของ Ken แต่ก็เพิ่มค่าเริ่มต้น:
function load(context) {
var defaults = {
parameter1: defaultValue1,
parameter2: defaultValue2,
...
};
var context = extend(defaults, context);
// do stuff
}
วิธีนี้หากคุณมีพารามิเตอร์จำนวนมาก แต่ไม่จำเป็นต้องตั้งค่าด้วยการเรียกใช้ฟังก์ชันแต่ละครั้งคุณสามารถระบุค่าเริ่มต้นที่ไม่ใช่ค่าเริ่มต้นได้ สำหรับวิธีการขยายคุณสามารถใช้วิธีการขยายของ jQuery ($.extend()
) ประดิษฐ์ของคุณเองหรือใช้วิธีการต่อไปนี้:
function extend() {
for (var i = 1; i < arguments.length; i++)
for (var key in arguments[i])
if (arguments[i].hasOwnProperty(key))
arguments[0][key] = arguments[i][key];
return arguments[0];
}
สิ่งนี้จะรวมวัตถุบริบทด้วยค่าเริ่มต้นและเติมค่าที่ไม่ได้กำหนดไว้ในวัตถุของคุณด้วยค่าเริ่มต้น
ใช่เช่นนี้:
function load()
{
var var0 = arguments[0];
var var1 = arguments[1];
}
load(1,2);
มันจะดีกว่าที่จะใช้ไวยากรณ์ส่วนที่เหลือเป็น Ramast ชี้ให้เห็น
function (a, b, ...args) {}
ฉันแค่ต้องการเพิ่มคุณสมบัติที่ดีของอาร์กิวเมนต์ ... args
- มันเป็นอาร์เรย์และไม่ใช่วัตถุเช่นการขัดแย้ง สิ่งนี้ช่วยให้คุณสามารถใช้ฟังก์ชั่นเช่นแผนที่หรือเรียงลำดับโดยตรง
- ไม่รวมพารามิเตอร์ทั้งหมด แต่มีเพียงพารามิเตอร์เดียวเท่านั้นที่ผ่านมา เช่นฟังก์ชัน (a, b, ... args) ในกรณีนี้ args มีอาร์กิวเมนต์ 3 ถึง arguments.length
ดังกล่าวแล้วคุณสามารถใช้ arguments
วัตถุเพื่อดึงหมายเลขตัวแปรของพารามิเตอร์ฟังก์ชั่น
หากคุณต้องการที่จะเรียกฟังก์ชั่นอื่น ๆ apply
ที่มีการขัดแย้งกันในการใช้งาน คุณสามารถเพิ่มหรือลบข้อโต้แย้งโดยแปลงarguments
เป็นอาเรย์ ตัวอย่างเช่นฟังก์ชั่นนี้จะแทรกข้อความบางส่วนก่อนที่จะเข้าสู่คอนโซล:
log() {
let args = Array.prototype.slice.call(arguments);
args = ['MyObjectName', this.id_].concat(args);
console.log.apply(console, args);
}
แม้ว่าโดยทั่วไปฉันยอมรับว่าวิธีการตั้งชื่ออาร์กิวเมนต์นั้นมีประโยชน์และยืดหยุ่น (เว้นแต่คุณสนใจเรื่องคำสั่งซึ่งในกรณีที่การโต้แย้งง่ายที่สุด) ฉันมีข้อกังวลเกี่ยวกับค่าใช้จ่ายของวิธีการ mbeasley (ใช้ค่าเริ่มต้นและขยาย) นี่เป็นค่าใช้จ่ายจำนวนมากสำหรับการดึงค่าเริ่มต้น ก่อนอื่นค่าเริ่มต้นจะถูกกำหนดไว้ภายในฟังก์ชั่นดังนั้นจึงมีการ repopulated ในทุกการโทร ประการที่สองคุณสามารถอ่านค่าที่ตั้งชื่อและตั้งค่าเริ่มต้นพร้อมกันได้อย่างง่ายดายโดยใช้ || ไม่จำเป็นต้องสร้างและรวมวัตถุใหม่อีกตัวเพื่อรับข้อมูลนี้
function load(context) {
var parameter1 = context.parameter1 || defaultValue1,
parameter2 = context.parameter2 || defaultValue2;
// do stuff
}
นี่คือจำนวนรหัสประมาณเท่ากัน (อาจมากกว่าเล็กน้อย) แต่ควรเป็นเศษส่วนของต้นทุนรันไทม์
(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)
หรือสำหรับปริมาณรหัสน้อยฟังก์ชั่นผู้ช่วยขนาดเล็กเช่น: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
ให้รูปแบบทางเลือก อย่างไรก็ตามจุดของฉันยังคงอยู่: การสร้างวัตถุพิเศษสำหรับทุกการเรียกใช้ฟังก์ชั่นและการใช้ลูปที่มีราคาแพงเพื่อตั้งค่าเริ่มต้นสองเท่าคือค่าใช้จ่ายจำนวนบ้า
ในขณะที่ @roufamatic ได้แสดงการใช้คำหลักอาร์กิวเมนต์และ @Ken แสดงตัวอย่างที่ยอดเยี่ยมของวัตถุสำหรับการใช้งานฉันรู้สึกว่าไม่ได้พูดถึงสิ่งที่เกิดขึ้นในตัวอย่างนี้อย่างแท้จริงและอาจทำให้ผู้อ่านในอนาคตสับสน / method มีวัตถุประสงค์เพื่อใช้จำนวนตัวแปรของอาร์กิวเมนต์ / พารามิเตอร์
function varyArg () {
return arguments[0] + arguments[1];
}
เมื่อนักพัฒนาซอฟต์แวร์คนอื่นดูรหัสของคุณมันง่ายมากที่จะสมมติว่าฟังก์ชั่นนี้ไม่ใช้พารามิเตอร์ โดยเฉพาะอย่างยิ่งหากนักพัฒนานั้นไม่ได้เป็นส่วนตัวกับข้อโต้แย้งคำหลักด้วยเหตุนี้จึงเป็นความคิดที่ดีที่จะทำตามแนวทางของสไตล์และสอดคล้องกัน ฉันจะใช้ Google เป็นตัวอย่างทั้งหมด
เรามาพูดถึงฟังก์ชั่นเดียวกันอย่างชัดเจนว่ามีพารามิเตอร์ตัวแปร:
function varyArg (var_args) {
return arguments[0] + arguments[1];
}
อาจมีบางครั้งที่จำเป็นต้องใช้วัตถุเนื่องจากเป็นวิธีปฏิบัติที่ดีที่สุดที่ได้รับอนุมัติและพิจารณาแล้วของแผนที่ข้อมูล อาเรย์เชื่อมโยงจะถูกหน้างอและท้อแท้
sidenote:คีย์เวิร์ดอาร์กิวเมนต์ส่งคืนอ็อบเจ็กต์ที่ใช้ตัวเลขเป็นคีย์ มรดกต้นแบบยังเป็นตระกูลของวัตถุด้วย ดูจุดสิ้นสุดของคำตอบสำหรับการใช้งานอาร์เรย์ที่เหมาะสมใน JS
ในกรณีนี้เราสามารถระบุได้อย่างชัดเจนเช่นกัน หมายเหตุ: ข้อตกลงการตั้งชื่อนี้ไม่ได้จัดทำโดย Google แต่เป็นตัวอย่างของการประกาศอย่างชัดเจนถึงประเภทของพารามิเตอร์ นี่เป็นสิ่งสำคัญหากคุณต้องการสร้างรูปแบบการพิมพ์ที่เข้มงวดยิ่งขึ้นในรหัสของคุณ
function varyArg (args_obj) {
return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});
ขึ้นอยู่กับความต้องการของฟังก์ชันและโปรแกรมของคุณ หากเช่นคุณเพียงแค่ต้องการส่งคืนค่าฐานในกระบวนการวนซ้ำในทุกอาร์กิวเมนต์ที่ส่งผ่านดังนั้นส่วนใหญ่จะยึดติดกับคีย์เวิร์ดอาร์กิวเมนต์ ถ้าคุณต้องการนิยามอาร์กิวเมนต์และการแม็พข้อมูลของคุณดังนั้นเมธอด object คือวิธีที่จะไป ลองดูตัวอย่างสองตัวอย่างจากนั้นก็เสร็จแล้ว!
function sumOfAll (var_args) {
return arguments.reduce(function(a, b) {
return a + b;
}, 0);
}
sumOfAll(1,2,3); // returns 6
function myObjArgs(args_obj) {
// MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
if (typeof args_obj !== "object") {
return "Arguments passed must be in object form!";
}
return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old
ตามที่กล่าวถึงด้านบนของคำตอบอาร์กิวเมนต์คำหลักส่งคืนวัตถุจริง ด้วยเหตุนี้วิธีการใด ๆ ที่คุณต้องการใช้สำหรับอาร์เรย์จะต้องถูกเรียก ตัวอย่างของสิ่งนี้:
Array.prototype.map.call(arguments, function (val, idx, arr) {});
เพื่อหลีกเลี่ยงปัญหานี้ให้ใช้พารามิเตอร์ส่วนที่เหลือ:
function varyArgArr (...var_args) {
return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
ใช้arguments
วัตถุเมื่ออยู่ภายในฟังก์ชั่นเพื่อให้สามารถเข้าถึงอาร์กิวเมนต์ทั้งหมดที่ส่งผ่าน
ระวังให้ดีว่าการส่ง Object ด้วยคุณสมบัติที่มีชื่อตามที่ Ken แนะนำจะเป็นการเพิ่มค่าใช้จ่ายในการจัดสรรและปล่อยวัตถุชั่วคราวไปยังการโทรทุกครั้ง การส่งผ่านข้อโต้แย้งปกติตามค่าหรือการอ้างอิงโดยทั่วไปจะมีประสิทธิภาพมากที่สุด สำหรับหลาย ๆ แอปพลิเคชั่น แต่ประสิทธิภาพไม่สำคัญ แต่สำหรับบางแอพพลิเคชั่น