ฉันอ่านคำถามนี้เกี่ยวกับ "ตัวดำเนินการลูกน้ำ" ในนิพจน์ ( ,
) และเอกสาร MDNเกี่ยวกับเรื่องนี้ แต่ฉันไม่สามารถนึกถึงสถานการณ์ที่เป็นประโยชน์ได้
ดังนั้นตัวดำเนินการลูกน้ำจึงมีประโยชน์เมื่อใด
ฉันอ่านคำถามนี้เกี่ยวกับ "ตัวดำเนินการลูกน้ำ" ในนิพจน์ ( ,
) และเอกสาร MDNเกี่ยวกับเรื่องนี้ แต่ฉันไม่สามารถนึกถึงสถานการณ์ที่เป็นประโยชน์ได้
ดังนั้นตัวดำเนินการลูกน้ำจึงมีประโยชน์เมื่อใด
,
ดำเนินการ บรรทัดนั้นก็ใช้ได้C#
เช่นกัน แต่,
ไม่มีตัวดำเนินการอยู่ที่นั่น
,
ไม่ใช่ตัว,
ดำเนินการเสมอไป(และไม่เคยเป็นตัว,
ดำเนินการใน C #) ดังนั้น C # จึงขาดตัว,
ดำเนินการในขณะที่ยังใช้,
เป็นส่วนหนึ่งของไวยากรณ์ได้อย่างอิสระ
,
ไม่ได้ใช้กันอย่างแพร่หลาย(และไม่ได้เกิดขึ้นของทุกคน,
เป็นผู้ดำเนินจุลภาค) แต่คุณสามารถยืมมันและ Array เพื่อทำการสลับตัวแปรแบบอินไลน์ได้โดยไม่ต้องสร้างตัวแปรชั่วคราว ระบุว่าคุณต้องการที่จะสลับค่าของa
และคุณสามารถทำb
a = [b][b = a,0]
ซึ่งจะวางกระแสb
ใน Array ประการที่สอง[]
คือสัญกรณ์การเข้าถึงคุณสมบัติ ดัชนีที่เข้าถึงนั้น0
ไม่ใช่ก่อนที่จะกำหนดa
ให้b
ซึ่งตอนนี้ปลอดภัยเนื่องจากb
จะถูกเก็บไว้ใน Array ช่วยให้เราทำสำนวนที่หลายแห่งใน,
[]
คำตอบ:
สิ่งต่อไปนี้อาจไม่มีประโยชน์มากนักเนื่องจากคุณไม่ได้เขียนเอง แต่ตัวย่อสามารถย่อโค้ดโดยใช้ตัวดำเนินการลูกน้ำ ตัวอย่างเช่น:
if(x){foo();return bar()}else{return 1}
จะกลายเป็น:
return x?(foo(),bar()):1
? :
ผู้ประกอบการสามารถนำมาใช้ในขณะนี้เนื่องจากผู้ประกอบการจุลภาค (ในระดับหนึ่ง) ช่วยให้สองงบที่จะเขียนเป็นคำสั่งอย่างใดอย่างหนึ่ง
สิ่งนี้มีประโยชน์ในการช่วยให้สามารถบีบอัดข้อมูลได้อย่างเรียบร้อย (39 -> 24 ไบต์ที่นี่)
ฉันต้องการที่จะเน้นความจริงที่ว่าจุลภาคในvar a, b
คือไม่ได้ประกอบจุลภาคเพราะมันไม่ได้อยู่ภายในการแสดงออก เครื่องหมายจุลภาคมีความหมายพิเศษในงบvar
a, b
ในการแสดงออกจะหมายถึงสองตัวแปรและประเมินผลการซึ่งไม่ได้เป็นกรณีที่b
var a, b
if (condition) var1 = val1, var2 = val2;
ส่วนตัวฉันคิดว่าการหลีกเลี่ยงวงเล็บที่เป็นไปได้ทำให้โค้ดอ่านง่ายขึ้น
ตัวดำเนินการลูกน้ำช่วยให้คุณใส่หลายนิพจน์ในตำแหน่งที่คาดว่าจะมีนิพจน์เดียว ค่าผลลัพธ์ของนิพจน์หลายรายการที่คั่นด้วยเครื่องหมายจุลภาคจะเป็นค่าของนิพจน์ที่คั่นด้วยลูกน้ำสุดท้าย
โดยส่วนตัวฉันไม่ได้ใช้บ่อยนักเพราะมีสถานการณ์ไม่มากนักที่คาดว่าจะมีนิพจน์มากกว่าหนึ่งนิพจน์และไม่มีวิธีการเขียนโค้ดที่สับสนน้อยไปกว่าการใช้ตัวดำเนินการลูกน้ำ ความเป็นไปได้ที่น่าสนใจอย่างหนึ่งคือตอนท้ายของfor
ลูปเมื่อคุณต้องการเพิ่มตัวแปรมากกว่าหนึ่งตัว:
// j is initialized to some other value
// as the for loop executes both i and j are incremented
// because the comma operator allows two statements to be put in place of one
for (var i = 0; i < items.len; i++, j++) {
// loop code here that operates on items[i]
// and sometimes uses j to access a different array
}
ที่นี่คุณจะเห็นว่าi++, j++
สามารถวางไว้ในตำแหน่งที่อนุญาตให้ใช้นิพจน์เดียวได้ ในกรณีนี้นิพจน์หลายตัวถูกใช้สำหรับผลกระทบด้านข้างดังนั้นจึงไม่สำคัญว่านิพจน์ผสมจะใช้กับค่าสุดท้าย แต่มีกรณีอื่น ๆ ที่อาจมีความสำคัญ
Comma Operator มักมีประโยชน์เมื่อเขียนโค้ดการทำงานใน Javascript
พิจารณารหัสนี้ที่ฉันเขียนสำหรับสปาในขณะที่ย้อนกลับไปซึ่งมีสิ่งต่อไปนี้
const actions = _.chain(options)
.pairs() // 1
.filter(selectActions) // 2
.map(createActionPromise) // 3
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
.value();
นี่เป็นสถานการณ์ที่ค่อนข้างซับซ้อน แต่ในโลกแห่งความจริง อดทนกับฉันในขณะที่ฉันอธิบายสิ่งที่เกิดขึ้นและในกระบวนการนี้จะทำให้ตัวดำเนินการเครื่องหมายจุลภาค
แยกตัวเลือกทั้งหมดที่ส่งผ่านไปยังฟังก์ชันนี้โดยใช้pairs
ซึ่งจะเปลี่ยน{ a: 1, b: 2}
เป็น[['a', 1], ['b', 2]]
อาร์เรย์ของคู่คุณสมบัตินี้ถูกกรองโดยที่ถือว่าเป็น 'การกระทำ' ในระบบ
จากนั้นดัชนีที่สองในอาร์เรย์จะถูกแทนที่ด้วยฟังก์ชันที่ส่งกลับคำสัญญาที่แสดงถึงการกระทำนั้น (โดยใช้map
)
ในที่สุดการเรียกร้องreduce
จะรวม "อาร์เรย์คุณสมบัติ" ( ['a', 1]
) แต่ละรายการกลับเป็นวัตถุสุดท้าย
ผลลัพธ์สุดท้ายคือoptions
อาร์กิวเมนต์เวอร์ชันที่แปลงแล้วซึ่งมีเฉพาะคีย์ที่เหมาะสมและมีค่าที่ฟังก์ชันการเรียกใช้งานได้
มองแค่
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
คุณสามารถเห็นฟังก์ชันลดเริ่มต้นด้วยอ็อบเจ็กต์สถานะว่างstate
และสำหรับแต่ละคู่ที่แสดงคีย์และค่าฟังก์ชันจะส่งคืนstate
อ็อบเจ็กต์เดียวกันหลังจากเพิ่มคุณสมบัติให้กับอ็อบเจ็กต์ที่สอดคล้องกับคู่คีย์ / ค่า เนื่องจากไวยากรณ์ของฟังก์ชันลูกศรของ ECMAScript 2015 เนื้อความของฟังก์ชันจึงเป็นนิพจน์และด้วยเหตุนี้ตัวดำเนินการเครื่องหมายจุลภาคจึงอนุญาตให้ใช้ฟังก์ชัน"iteratee" ที่กระชับและมีประโยชน์
โดยส่วนตัวแล้วฉันเจอหลายกรณีในขณะที่เขียน Javascript ในรูปแบบที่ใช้งานได้มากขึ้นด้วย ECMAScript 2015 + Arrow Functions ต้องบอกว่าก่อนที่จะพบกับฟังก์ชันลูกศร (เช่นในขณะที่เขียนคำถาม) ฉันไม่เคยใช้ตัวดำเนินการลูกศรในทางที่ตั้งใจ
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
ที่สามารถอ่านเพิ่มเติมได้ที่: และฉันตระหนักดีว่าสิ่งนี้เอาชนะจุดประสงค์ของคำตอบ แต่.reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
จะขจัดความจำเป็นในการใช้ตัวดำเนินการลูกน้ำทั้งหมด
การใช้ตัวดำเนินการลูกน้ำอีกอย่างหนึ่งคือการซ่อนผลลัพธ์ที่คุณไม่สนใจในการจำลองหรือคอนโซลเพียงเพื่อความสะดวก
ตัวอย่างเช่นหากคุณประเมินmyVariable = aWholeLotOfText
ในการจำลองหรือคอนโซลระบบจะพิมพ์ข้อมูลทั้งหมดที่คุณเพิ่งกำหนดให้ ซึ่งอาจเป็นเพจและเพจต่างๆและหากคุณไม่ต้องการเห็นคุณสามารถประเมินแทนได้myVariable = aWholeLotOfText, 'done'
และ repl / console จะพิมพ์แค่ 'เสร็จสิ้น'
Oriel อย่างถูกต้องชี้ให้เห็น†ที่กำหนดเองtoString()
หรือget()
ฟังก์ชั่นก็อาจจะทำให้มีประโยชน์นี้
ประกอบจุลภาคคือไม่เฉพาะ JavaScript, มันมีอยู่ในภาษาอื่น ๆ เช่นC และ C ++ ในฐานะตัวดำเนินการไบนารีสิ่งนี้มีประโยชน์เมื่อตัวถูกดำเนินการตัวแรกซึ่งโดยทั่วไปเป็นนิพจน์มีผลข้างเคียงที่ต้องการโดยตัวถูกดำเนินการที่สอง ตัวอย่างหนึ่งจาก wikipedia:
i = a += 2, a + b;
เห็นได้ชัดว่าคุณสามารถเขียนโค้ดได้ 2 บรรทัด แต่การใช้ลูกน้ำเป็นอีกทางเลือกหนึ่งและบางครั้งก็อ่านได้มากกว่า
ฉันไม่เห็นด้วยกับฟลานาแกนและบอกว่าลูกน้ำนั้นมีประโยชน์มากและช่วยให้เขียนโค้ดที่อ่านง่ายและสวยงามมากขึ้นโดยเฉพาะเมื่อคุณรู้ว่าคุณกำลังทำอะไรอยู่:
นี่คือบทความโดยละเอียดเกี่ยวกับการใช้งานจุลภาค:
ตัวอย่างมากมายจากที่นั่นเพื่อพิสูจน์การสาธิต:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) {
console.log(new Array(a*b).join('*'));
}
}
เครื่องกำเนิด fibonacci:
for (
var i=2, r=[0,1];
i<15;
r.push(r[i-1] + r[i-2]), i++
);
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377
ค้นหาองค์ประกอบหลักแรกอะนาล็อกของ.parent()
ฟังก์ชันjQuery :
function firstAncestor(el, tagName) {
while(el = el.parentNode, el && (el.tagName != tagName.toUpperCase()));
return el;
}
//element in http://ecma262-5.com/ELS5_HTML.htm
var a = $('Section_15.1.1.2');
firstAncestor(a, 'div'); //<div class="page">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
ก็ใช้ได้ดีในบริบทนั้น
ฉันไม่พบการใช้งานจริงนอกเหนือจากนั้น แต่นี่เป็นสถานการณ์หนึ่งที่James Padolseyใช้เทคนิคนี้อย่างดีในการตรวจจับ IEแบบวนซ้ำ:
var ie = (function(){
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while ( // <-- notice no while body here
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}());
สองบรรทัดนี้ต้องดำเนินการ:
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
และภายในตัวดำเนินการลูกน้ำทั้งสองจะได้รับการประเมินแม้ว่าจะมีใครทำให้แยกกัน
do
- while
วนซ้ำ
มีบางอย่าง "แปลก" ที่สามารถทำได้ใน JavaScript ที่เรียกใช้ฟังก์ชันทางอ้อมโดยใช้ตัวดำเนินการลูกน้ำ
มีคำอธิบายแบบยาวที่นี่: การเรียกฟังก์ชันทางอ้อมใน JavaScript
โดยใช้ไวยากรณ์นี้:
(function() {
"use strict";
var global = (function () { return this || (1,eval)("this"); })();
console.log('Global === window should be true: ', global === window);
var not_global = (function () { return this })();
console.log('not_global === window should be false: ', not_global === window);
}());
คุณสามารถเข้าถึงตัวแปรส่วนกลางได้เนื่องจากeval
ทำงานแตกต่างกันเมื่อเรียกโดยตรงกับเรียกโดยอ้อม
ฉันพบว่าตัวดำเนินการลูกน้ำมีประโยชน์มากที่สุดเมื่อเขียนตัวช่วยเช่นนี้
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
คุณสามารถแทนที่จุลภาคด้วย || หรือ && แต่คุณต้องรู้ว่าฟังก์ชันส่งคืนอะไร
สิ่งที่สำคัญกว่านั้นตัวคั่นด้วยเครื่องหมายจุลภาคจะสื่อถึงเจตนา - รหัสไม่สนใจว่าตัวถูกดำเนินการด้านซ้ายจะประเมินว่าเป็นอย่างไรในขณะที่ทางเลือกอื่นอาจมีเหตุผลอื่นในการอยู่ที่นั่น สิ่งนี้ทำให้ง่ายต่อการทำความเข้าใจและ refactor หากประเภทการส่งคืนฟังก์ชันเปลี่ยนแปลงไปโค้ดด้านบนจะไม่ได้รับผลกระทบ
โดยปกติแล้วคุณสามารถทำสิ่งเดียวกันได้ด้วยวิธีอื่น แต่ไม่รวบรัดเท่า ถ้า || และ && พบสถานที่ในการใช้งานทั่วไปตัวดำเนินการลูกน้ำก็เช่นกัน
tap
( ramdajs.com/docs/#tap ) โดยพื้นฐานแล้วคุณกำลังเรียกใช้ผลข้างเคียงจากนั้นคืนค่าเริ่มต้น มีประโยชน์มากในการเขียนโปรแกรมเชิงฟังก์ชัน :)
กรณีทั่วไปอย่างหนึ่งที่ฉันใช้มันคือระหว่างการแยกวิเคราะห์อาร์กิวเมนต์ที่เป็นทางเลือก ฉันคิดว่ามันทำให้ทั้งอ่านง่ายและกระชับมากขึ้นเพื่อให้การแยกวิเคราะห์อาร์กิวเมนต์ไม่ครอบงำเนื้อความ
/**
* @param {string} [str]
* @param {object} [obj]
* @param {Date} [date]
*/
function f(str, obj, date) {
// handle optional arguments
if (typeof str !== "string") date = obj, obj = str, str = "default";
if (obj instanceof Date) date = obj, obj = {};
if (!(date instanceof Date)) date = new Date();
// ...
}
สมมติว่าคุณมีอาร์เรย์:
arr = [];
เมื่อคุณpush
เข้าสู่อาร์เรย์นั้นคุณจะไม่ค่อยสนใจในpush
ค่าตอบแทนของอาร์เรย์นั่นคือความยาวใหม่ของอาร์เรย์ แต่เป็นอาร์เรย์เอง:
arr.push('foo') // ['foo'] seems more interesting than 1
ด้วยการใช้ตัวดำเนินการลูกน้ำเราสามารถพุชเข้าสู่อาร์เรย์ระบุอาร์เรย์เป็นตัวถูกดำเนินการสุดท้ายเป็นเครื่องหมายจุลภาคจากนั้นใช้ผลลัพธ์ - อาร์เรย์เอง - สำหรับการเรียกเมธอดอาร์เรย์ที่ตามมาการเรียงลำดับของการเชื่อมโยง:
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
พื้นที่ที่ผู้ประกอบการจุลภาคสามารถนำมาใช้ก็คือรหัส Obfuscation
สมมติว่าผู้พัฒนาเขียนโค้ดดังนี้:
var foo = 'bar';
ตอนนี้เธอตัดสินใจที่จะทำให้รหัสสับสน เครื่องมือที่ใช้อาจเปลี่ยนรหัสดังนี้:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
การสาธิต: http://jsfiddle.net/uvDuE/
var i, j, k;
VSvar i; var j, var k
?