เหตุใดจึงต้องหลีกเลี่ยงตัวดำเนินการเพิ่ม (“ ++”) และตัวลด (“ -”) ใน JavaScript


357

หนึ่งในเคล็ดลับสำหรับเครื่องมือ jslintคือ:

++ และ -
ผู้ประกอบการ ++ (เพิ่มขึ้น) และ - (ลดลง) ได้รับการรู้จักในการมีส่วนร่วมกับรหัสที่ไม่ดีโดยการส่งเสริมความยุ่งยากมากเกินไป พวกเขาเป็นที่สองเท่านั้นที่สถาปัตยกรรมผิดพลาดในการเปิดใช้งานไวรัสและภัยคุกคามความปลอดภัยอื่น ๆ มีตัวเลือก plusplus ที่ห้ามการใช้งานของผู้ประกอบการเหล่านี้

ฉันรู้ว่า PHP สร้างเหมือน$foo[$bar++]มีได้อย่างง่ายดายอาจส่งผลกับการปิดโดยหนึ่งข้อผิดพลาด แต่ฉันไม่สามารถคิดออกวิธีที่ดีกว่าที่จะควบคุมห่วงกว่าที่หรือwhile( a < 10 ) do { /* foo */ a++; }for (var i=0; i<10; i++) { /* foo */ }

jslint เน้นที่ภาษานั้นเพราะมีบางภาษาที่คล้ายกันที่ไม่มีไวยากรณ์ " ++" และ " --" หรือจัดการแตกต่างกันหรือมีเหตุผลอื่น ๆ ที่จะหลีกเลี่ยง " ++" และ " --" ที่ฉันอาจหายไป?


59
ดังนั้นหนึ่งควรทำอาร์เรย์ [ดัชนี = ดัชนี + 1] แทนอาร์เรย์ [++ ดัชนี] (ถ้าอดีตได้รับอนุญาตแม้แต่!) ช่างเป็นภาระอะไร
Lawrence Dol

34
ฉันไม่เห็น Crockford do index = index + 1 ฉันเคยเห็นเขาทำดัชนี + = 1 ฉันคิดว่านั่นเป็นทางเลือกที่สมเหตุสมผล และมันเป็นเรื่องดีสำหรับเมื่อคุณต้องการที่จะเปลี่ยนกางเกงเพื่อสิ่งที่นอกเหนือจาก 1.
Nosredna

124
โดยส่วนตัวฉันไม่ใช่แฟนตัวยงของ Crockford ดูเหมือนว่าเขาจะคิดว่าอะไรก็ตามที่ทำให้เกิดข้อผิดพลาดในรหัสของเขาเป็นความชั่วร้าย
เปาโล Bergantino

38
ในจาวาสคริปต์คุณควรพิจารณาว่าบั๊กทุกตัวค่อนข้างเลวร้ายเนื่องจากไม่มีเอกสารอย่างเป็นทางการและไม่มีผู้ให้บริการออกใบรับรองหรือคุณเรียนรู้ JS อย่างถูกต้องในมหาวิทยาลัย Crockford และ Firebug เติมเต็มช่องโหว่เหล่านี้ในการศึกษา JavaScript
stevek

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

คำตอบ:


408

มุมมองของฉันคือการใช้ ++ และ - ด้วยตัวเองในบรรทัดเดียวเสมอใน:

i++;
array[i] = foo;

แทน

array[++i] = foo;

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


3
ใช่นั่นคือสิ่งที่ฉันทำเช่นกัน ยากที่จะผิดพลาดและง่ายกว่าที่คนอื่นจะเข้าใจว่าคุณกำลังทำอะไรอยู่
Nosredna

65
ดูเหมือนว่าจะเป็นแกนหลักของปัญหาและความสับสนของฉัน ใช้คนเดียว i ++; มีความใส นาทีที่คุณเพิ่มโค้ดอื่น ๆ รอบ ๆ นิพจน์พื้นฐานความสามารถในการอ่านและความคมชัดจะเริ่มต้นขึ้น
artlung

2
เห็นด้วย แต่ไม่ใช่แค่เกี่ยวกับ JavaScript เท่านั้น
Tobias

5
คุณไม่ได้พูดว่าคุณกำลังเขียน C หรือ C ++ คุณควรใช้โอเปอเรเตอร์การเพิ่มคำนำหน้าใน C ++ ในกรณีที่iตัวแปรกลายเป็นคอมโพสิตในภายหลังซึ่งในกรณีนี้คุณจะสร้างวัตถุชั่วคราวโดยไม่จำเป็น ฉันพบว่าผู้ประกอบการ postfix ชื่นชอบมากขึ้น
mc0e

2
ฉันชอบเวอร์ชั่น 1 บรรทัด มันเตือนการดำเนินการสแต็ค push is array [++ i] = foo, pop is bar = array [i--] (แต่ด้วย 0 ที่ใช้อาร์เรย์อาร์เรย์ [i ++] = foo และ bar = array [- i] ดูยังดีกว่า) อีกอย่างฉันจะเกลียดถ้ามีคนเพิ่มรหัสพิเศษระหว่าง i ++; และอาร์เรย์ [i] = foo;
Florian F

257

ฉันสับสนตรงไปตรงมาโดยคำแนะนำนั้น ส่วนหนึ่งของฉันสงสัยว่ามันเกี่ยวข้องกับการขาดประสบการณ์ (การรับรู้หรือจริง) กับ javascript coders

ฉันเห็นได้ว่ามีใครบางคนแค่ "แฮ็ค" ในบางตัวอย่างโค้ดอาจทำผิดพลาดอย่างไร้เดียงสาด้วย ++ และ - แต่ฉันไม่เห็นว่าทำไมผู้เชี่ยวชาญที่มีประสบการณ์จะหลีกเลี่ยง


7
จุดที่ดีจอน B. นั่นคือเหตุผลที่ทำให้ฉันรำคาญ คร็อคฟอร์ดเป็นโปรแกรมเมอร์มืออาชีพ (มีค่าหลายสิบปี) มีความเชี่ยวชาญในหลายภาษาตลอดหลายทศวรรษที่ผ่านมาและทำงานร่วมกับ JavaScript โดยพื้นฐานนับตั้งแต่ก่อตั้งขึ้น ฉันไม่คิดว่าคำแนะนำของเขามาจาก "ฉันขี้เกียจและไม่ตั้งใจแฮ็กเกอร์ที่ไม่มีประสบการณ์" - นั่นเป็นเหตุผลที่ฉันพยายามเข้าใจว่ามาจากไหน
artlung

14
@artlung อาจเป็นเรื่องเกี่ยวกับ "แฮ็กเกอร์ที่ขี้เกียจและไม่มีประสบการณ์" อาจจะยุ่งกับโค้ดนี้และฉันไม่ต้องการทำให้เขาสับสน
Chris Cudmore

9
ฉันไม่เห็นด้วยกับคำตอบของคุณ ในความคิดของฉันมันไม่เกี่ยวกับ 'ฉันมีประสบการณ์เพียงพอที่จะใช้หรือไม่' - แต่ 'ชัดเจนหรือไม่?' หากอยู่ในวงวนหรืออยู่คนเดียวก็ชัดเจนว่าทุกคนจะเข้าใจว่าไม่มีอันตรายใด ๆ ปัญหาเกิดขึ้นเมื่อใส่++นิพจน์ที่ซับซ้อนมากขึ้นใน wich ++ x จะแตกต่างจาก x ++ ดังนั้นจึงทำให้อ่านไม่สะดวก แนวคิดของ Crockford ไม่ได้เกี่ยวกับ 'ฉันจะทำมันได้หรือไม่' เกี่ยวกับ 'ฉันจะหลีกเลี่ยงข้อผิดพลาดได้อย่างไร'
ArtoAle

1
เป็นความชอบส่วนตัวในสิ่งที่ความคมชัดของจุดสำคัญกับคุณมากกว่าความกะทัดรัด สิ่งนี้นอกเหนือไปจากประสบการณ์ที่มากพอที่จะเข้าใจโค้ด ดูคำตอบอื่น ๆ สำหรับตัวอย่างที่มีปัญหามากกว่าความคุ้มค่า
Frug

1
ฉันเห็นด้วยอย่างยิ่ง ทำไมต้องฝึกให้ตัวเองโดยไม่ใช้ภาษาบางส่วน? ฉันพบว่ามีเหตุผลที่ดีสำหรับการใช้ทั้งการโพสต์และการเพิ่มขึ้นและลดลง สำหรับฉันบรรทัดแบบนี้ชัดเจนและรัดกุม ... ถ้า (--imagesLoading === 0) เริ่มต้น (); หากคุณคิดว่ารหัสของคุณไม่ชัดเจนให้ใช้ความคิดเห็น!
xtempore

69

มีประวัติในการทำสิ่ง C เช่น:

while (*a++ = *b++);

เพื่อคัดลอกสตริงบางทีนี่อาจเป็นที่มาของกลอุบายที่มากเกินไปที่เขาอ้างถึง

และมีคำถามอะไรอยู่เสมอ

++i = i++;

หรือ

i = i++ + ++i;

ทำจริง มันถูกกำหนดในบางภาษาและในอีกภาษาหนึ่งไม่มีการรับประกันว่าจะเกิดอะไรขึ้น

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


104
i = i ++ + ++ i; ทำให้ตาของฉันเจ็บน้อย - :)
Hugoware

3
ของฉันด้วย. แม้ว่าพวกเขาจะไม่ได้ตัวแปรเดียวกันทั้งหมดบอกว่าฉันมี x = a ++ + ++ b; - การรวมกันนั้นทำให้ x, a และ b ถือยากขึ้นในหัวของฉัน ตอนนี้ถ้าแต่ละคำสั่งแยกกันในบรรทัดที่แยกกันเช่นใน - a ++; ++ ข; x = a + b; มันจะง่ายกว่าที่จะเข้าใจตั้งแต่แรกเห็น
artlung

10
อนิจจา (a ++; b ++; x = a = b) ไม่ใช่ค่าเดียวกันกับ (a ++ + ++ b)
Thomas L Holaday

8
@Marius: x = a+++b-> ->x = (a++)+b x = a + b; a++tokeniser นั้นโลภมาก
Callum Rogers

14
เพื่อความปลอดภัยในการทำงานเพิ่มเติมให้ลบช่องว่างในตัวอย่างสุดท้ายของคุณ
mc0e

48

หากคุณอ่าน JavaScript The Good Parts คุณจะเห็นว่าการแทนที่ Crockford สำหรับ i ++ ใน a for loop คือ i + = 1 (ไม่ใช่ i = i + 1) นั่นสะอาดและอ่านง่ายและมีโอกาสน้อยที่จะแปรเปลี่ยนเป็นบางสิ่งที่ "ยุ่งยาก"

Crockford ไม่อนุญาตการเก็บข้อมูลอัตโนมัติและการเลือกสร้างอัตโนมัติใน jsLint คุณเลือกว่าจะทำตามคำแนะนำหรือไม่

กฎส่วนบุคคลของฉันคือการไม่ทำอะไรรวมกับการสร้างอัตโนมัติหรือการสร้างอัตโนมัติ

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

ดังนั้นสำหรับกฎของฉันเองการใช้ i ++ เป็นการเพิ่มใน a for loop นั้นใช้ได้


จุดที่ยอดเยี่ยมเกี่ยวกับตัวเลือก "plusplus" เป็นเพียงตัวเลือกนั้น จากคำตอบของคุณและคำตอบอื่น ๆ ฉันคิดว่าฉันรู้สึกว่า ++ โดยตัวของมันเองหรือ for-loop นั้นไม่ได้ทำให้เกิดความสับสน วินาทีที่คุณรวม ++ นั้นเข้ากับคำแถลงอื่นที่คุณใช้คำสั่ง r จะยากต่อการอ่านและทำความเข้าใจในบริบท
artlung

6
ทุกคนได้รับบัฟเฟอร์ล้น แม้ OpenSSH กับเปิดแหล่งที่มาของพวกเขาและหลาย comitees ของพวกเขาในการแก้ไข
เอริค

11
@Eric ทบทวนความคิดเห็นห้าปีของคุณอีกครั้ง: โอ้ใช่แล้ว!
wchargin

27

ในการวนซ้ำมันไม่เป็นอันตราย แต่ในคำสั่งการมอบหมายมันสามารถนำไปสู่ผลลัพธ์ที่ไม่คาดคิด:

var x = 5;
var y = x++; // y is now 5 and x is 6
var z = ++x; // z is now 7 and x is 7

ช่องว่างระหว่างตัวแปรและตัวดำเนินการสามารถนำไปสู่ผลลัพธ์ที่ไม่คาดคิดเช่นกัน:

a = b = c = 1; a ++ ; b -- ; c; console.log('a:', a, 'b:', b, 'c:', c)

ผลลัพธ์ที่ไม่คาดคิดอาจเป็นปัญหาเช่นกัน:

var foobar = function(i){var count = count || i; return function(){return count++;}}

baz = foobar(1);
baz(); //1
baz(); //2


var alphabeta = function(i){var count = count || i; return function(){return ++count;}}

omega = alphabeta(1);
omega(); //2
omega(); //3

และก่อให้เกิดการแทรกอัฒภาคอัตโนมัติหลังจากขึ้นบรรทัดใหม่:

var foo = 1, bar = 2, baz = 3, alpha = 4, beta = 5, delta = alpha
++beta; //delta is 4, alpha is 4, beta is 6

ความสับสนของการ preincrement / postincrement สามารถสร้างข้อผิดพลาดแบบหนึ่งต่อหนึ่งซึ่งยากต่อการวินิจฉัย โชคดีที่พวกเขายังไม่จำเป็นโดยสมบูรณ์ มีวิธีที่ดีกว่าในการเพิ่ม 1 ให้กับตัวแปร

อ้างอิง


13
แต่พวกเขาจะไม่ "คาดไม่ถึง" ถ้าคุณเข้าใจผู้ปฏิบัติงาน มันเหมือนไม่เคยใช้==เพราะคุณไม่เข้าใจความแตกต่างระหว่างและ== ===
greg84

1
เผง มีคำถาม C #ซึ่งหักล้างสมมติฐานที่ผิดพลาด
พอล Sweatte

ฉันคิดว่าประเด็นของ Crockford คือโปรแกรมเมอร์ส่วนใหญ่ไม่เข้าใจ "ผู้ปฏิบัติงาน" อย่างเต็มที่แม้ว่าพวกเขาคิดว่าพวกเขาทำ ดังนั้นจึงมีอันตรายในการใช้งานเนื่องจากศักยภาพของความเข้าใจผิดสูง ดูความคิดเห็นของ @ Paul เกี่ยวกับสมมติฐานที่ผิดซึ่งสนับสนุนการโต้แย้งที่คนทั่วไปเข้าใจผิดว่าคำนำหน้าและตัวดำเนินการ postfix ทำงานอย่างไร ที่กล่าวว่าฉันยอมรับว่าฉันชอบที่จะใช้พวกเขา แต่เพื่อประโยชน์ของผู้อื่นฉันพยายามที่จะ จำกัด การใช้ของพวกเขาเพื่อกรณีที่เป็นสำนวน (ดูคำตอบของ cdmckay )
gfullam

ดูเหมือนว่าลิงก์ช่องว่างของคุณจะใช้งานไม่ได้
Ruslan

อะไรคือสิ่งที่ยุ่งยากเกี่ยวกับตัวอย่าง "ช่องว่าง" ของคุณ a: 2 b: 0 c: 1ฉันได้รับการส่งออกตรงไปตรงมา ฉันไม่เห็นอะไรแปลก ๆ หรือคาดไม่ถึงในตัวอย่างแรก ("คำสั่งการมอบหมาย") เช่นกัน
Ken Williams

17

พิจารณารหัสต่อไปนี้

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[i++] = i++;
    a[i++] = i++;
    a[i++] = i++;

เนื่องจาก i ++ ได้รับการประเมินสองครั้งผลลัพธ์คือ (จาก vs2005 ดีบักเกอร์)

    [0] 0   int
    [1] 0   int
    [2] 2   int
    [3] 0   int
    [4] 4   int

พิจารณารหัสต่อไปนี้:

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[++i] = ++i;
    a[++i] = ++i;
    a[++i] = ++i;

ขอให้สังเกตว่าการส่งออกเหมือนกัน ตอนนี้คุณอาจคิดว่า ++ i และ i ++ เหมือนกัน พวกเขาจะไม่

    [0] 0   int
    [1] 0   int
    [2] 2   int
    [3] 0   int
    [4] 4   int

ในที่สุดพิจารณารหัสนี้

    int a[10];
    a[0] = 0;
    a[1] = 0;
    a[2] = 0;
    a[3] = 0;
    int i = 0;
    a[++i] = i++;
    a[++i] = i++;
    a[++i] = i++;

ผลลัพธ์คือ:

    [0] 0   int
    [1] 1   int
    [2] 0   int
    [3] 3   int
    [4] 0   int
    [5] 5   int

ดังนั้นพวกเขาจึงไม่เหมือนกันการผสมทั้งสองอย่างทำให้เกิดพฤติกรรมที่ไม่คุ้นเคย ฉันคิดว่าสำหรับลูปใช้ได้กับ ++ แต่ระวังเมื่อคุณมีสัญลักษณ์หลาย ++ บนบรรทัดเดียวกันหรือคำสั่งเดียวกัน


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

28
ฉันหยุดหลังจากตัวอย่างแรก คุณพูดว่า "พิจารณารหัสต่อไปนี้" ไม่ไม่มีใครเขียนรหัสนั้น มันเป็นคนงี่เง่าที่เขียนว่าใครมีข้อบกพร่องไม่ใช่ภาษาสร้าง
Sam Harwell

4
คุณได้แสดงให้เห็นว่าโค้ดสองส่วนที่แตกต่างกันนั้นให้ผลลัพธ์ที่แตกต่างกันและนี่เป็นการพิสูจน์ว่าไม่ดีใช่หรือไม่
nickf

7
ข้อสรุปคือ "ระวังเมื่อคุณมีสัญลักษณ์ ++ หลายอันในบรรทัดเดียวกันหรือคำสั่งเดียวกัน" ฉันไม่คิดว่าคุณจะอ่านมัน
Eric

1
"เนื่องจาก i ++ ได้รับการประเมินสองครั้ง" - ผิด! การแก้ไขตัวแปรสองครั้งระหว่างจุดลำดับและการใช้มันไม่ถูกต้องใน C ++ และนำไปสู่พฤติกรรมที่ไม่ได้กำหนด ดังนั้นคอมไพเลอร์อาจทำสิ่งที่มันต้องการ ผลลัพธ์ที่นำเสนอที่นี่เป็นอุบัติเหตุของการใช้งานคอมไพเลอร์
tbleher

16

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


29
ตกลงกัน; อย่างไรก็ตามผู้เชี่ยวชาญที่มีประสบการณ์ไม่ควรสับสน
Nate

1
ฉันคิดว่านี่คล้ายกับแนวทางเพื่อหลีกเลี่ยงการทำให้ทุกอย่างคงที่หรือเป็นสากล ไม่มีอะไรผิดปกติกับมันเป็นโครงสร้างการเขียนโปรแกรม แต่การใช้มากเกินไปไม่รู้อาจนำไปสู่รหัสที่ไม่ดี
Joel Martinez

6
คำถามไม่ใช่ว่าโปรแกรมเมอร์ที่ดีสามารถ "ทำงานตามวิธี" ผ่านตรรกะได้หรือไม่รหัสที่ดีนั้นไม่จำเป็นต้องมีงานที่จะเข้าใจ ฉันคิดว่าประเด็นของ McWafflestix ก็คือคุณไม่ควรเขียนโค้ดว่าเมื่อตรวจสอบสั้น ๆ อาจนำไปสู่การเพิ่มข้อบกพร่องในสองสัปดาห์หรือสองปี ฉันรู้ว่าฉันได้รับความผิดของการเพิ่มรหัสประจำผมไม่เข้าใจอย่างเต็มที่ :)
ไมค์

1
@ ไมค์: ใช่สังเกตว่าฉันไม่ได้ระบุว่าโอเปอเรเตอร์อาจเป็นเรื่องยากสำหรับผู้เขียนรหัสดั้งเดิมหรือสำหรับผู้ดูแลในภายหลัง โดยทั่วไปเราพยายามที่จะสมมติว่าตัวแปลงสัญญาณดั้งเดิมไม่ได้ใช้โครงสร้างที่ไม่คุ้นเคย / คุ้นเคย (น่าเศร้านี่เป็นข้อสันนิษฐานที่ไม่ถูกต้องบ่อยครั้ง) อย่างไรก็ตามความคุ้นเคยนั้นไม่ได้ขยายไปถึงผู้ดูแล (และตามที่กล่าวไว้ในวงเล็บข้างต้นอาจไม่ขยายไปถึงผู้เขียนดั้งเดิม)
Paul Sonier

ฉันพยายามเขียนโค้ดเพื่อให้โปรแกรมเมอร์คนอื่นอ่าน แต่ฉันไม่พยายามเขียนเพื่อให้ผู้เริ่มต้นอ่าน
ลุคเอช

16

ในมุมมองของฉัน"ชัดเจนกว่าดีกว่าเสมอ" y+ = x++ + ++yเพราะในบางจุดที่คุณอาจได้สับสนกับคำสั่งที่เพิ่มขึ้นนี้ โปรแกรมเมอร์ที่ดีจะทำให้โค้ดของเขาหรือเธออ่านง่ายขึ้น


1
ไม่มีนัยใน x ++ หรือ ++ y
Florian F

1
สิ่งที่โค้ดที่อ่านได้นี้เป็นเรื่องยาก ... ฉันคิดว่ามีบรรทัดพื้นฐานว่าโค้ดของคุณควรเป็นอย่างไรและเรา - ชุมชน - ต้องเจริญเติบโตได้เล็กน้อยและสามารถอ่านสิ่งที่ไม่สามารถอ่านได้ในตอนนี้เช่น One-liners ด้วย ternaries ที่ซ้อนกันเพื่อให้มีสิ่งต่างๆมากมายที่จะเตะเข้ามา
Hamza Ouaghad

14

เหตุผลที่สำคัญที่สุดสำหรับการหลีกเลี่ยง ++ หรือ - คือตัวดำเนินการคืนค่าและทำให้เกิดผลข้างเคียงในเวลาเดียวกันทำให้ยากที่จะให้เหตุผลเกี่ยวกับรหัส

เพื่อประโยชน์ของประสิทธิภาพฉันชอบ:

  • ++ ฉันเมื่อไม่ได้ใช้ค่าส่งคืน (ไม่มีชั่วคราว)
  • i ++เมื่อใช้ค่าส่งคืน (ไม่มีแผงลอยไปป์ไลน์)

ฉันเป็นแฟนตัวยงของ Mr. Crockford แต่ในกรณีนี้ฉันต้องไม่เห็นด้วย ++iข้อความที่มีการแยกวิเคราะห์น้อยกว่า 25% i+=1 และชัดเจนยิ่งขึ้น


13

ฉันเคยดูวิดีโอของ Douglas Crockford เกี่ยวกับเรื่องนี้และคำอธิบายของเขาที่ไม่ได้ใช้การเพิ่มและลดก็คือ

  1. มันถูกนำมาใช้ในอดีตในภาษาอื่น ๆ เพื่อทำลายขอบเขตของอาร์เรย์และก่อให้เกิดมารยาทที่เลวร้ายและ
  2. มันเป็นเรื่องที่สับสนและไม่มีประสบการณ์มากนักพัฒนา JS ไม่รู้ว่ามันทำอะไร

ประการแรกอาร์เรย์ใน JavaScript มีขนาดแบบไดนามิกและโปรดยกโทษให้ฉันถ้าฉันผิดฉันไม่สามารถทำลายขอบเขตของอาร์เรย์และข้อมูลการเข้าถึงที่ไม่ควรเข้าถึงได้โดยใช้วิธีนี้ใน JavaScript

ประการที่สองเราควรหลีกเลี่ยงสิ่งที่ซับซ้อนแน่นอนปัญหาไม่ใช่ว่าเรามีสิ่งอำนวยความสะดวกนี้ แต่ปัญหาคือมีนักพัฒนาออกมีที่อ้างว่าทำ JavaScript แต่ไม่รู้ว่าผู้ประกอบการเหล่านี้ทำงานอย่างไร? มันง่ายพอ value ++ ให้ค่าปัจจุบันกับฉันและหลังจากนิพจน์บวกหนึ่งค่าไปยังค่า ++ ให้เพิ่มค่าก่อนที่จะมอบให้ฉัน

นิพจน์เช่น a ++ + ++ b นั้นง่ายต่อการออกกำลังกายถ้าคุณจำข้างต้น

var a = 1, b = 1, c;
c = a ++ + ++ b;
// c = 1 + 2 = 3; 
// a = 2 (equals two after the expression is finished);
// b = 2;

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

Btw ฉันคิดว่า Douglas Crockford เป็นตำนานอยู่แล้ว แต่ฉันคิดว่าเขาสร้างความหวาดกลัวให้กับโอเปอเรเตอร์ที่ไม่สมควรได้รับมันมากมาย

ฉันมีชีวิตอยู่เพื่อพิสูจน์ว่าผิด ...


10

อีกตัวอย่างหนึ่งง่ายกว่าบางคนด้วยการคืนค่าที่เพิ่มขึ้นอย่างง่าย ๆ :

function testIncrement1(x) {
    return x++;
}

function testIncrement2(x) {
    return ++x;
}

function testIncrement3(x) {
    return x += 1;
}

console.log(testIncrement1(0)); // 0
console.log(testIncrement2(0)); // 1
console.log(testIncrement3(0)); // 1

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

function closureIncrementTest() {
    var x = 0;

    function postIncrementX() {
        return x++;
    }

    var y = postIncrementX();

    console.log(x); // 1
}

หนึ่งในฟังก์ชันของคุณเท่านั้นที่ได้รับ x เป็นพารามิเตอร์
Calimero100582

8

ฉันคิดว่าโปรแกรมเมอร์ควรมีความสามารถในภาษาที่ใช้ ใช้อย่างชัดเจน และใช้งานได้ดี ฉันไม่คิดว่าพวกเขาควรทำลายภาษาที่พวกเขาใช้ ฉันพูดจากประสบการณ์ ครั้งหนึ่งฉันเคยทำงานใกล้ ๆ กับร้าน Cobol ที่พวกเขาไม่ได้ใช้ ELSE เพราะมันซับซ้อนเกินไป Reductio ad absurdam


@downvoter ที่น่าสนใจ คุณไม่คิดว่าโปรแกรมเมอร์ควรมีความสามารถในภาษาหรือไม่ คุณคิดว่าพวกเขาควรทำลายภาษาเทียมหรือไม่? มันคืออะไร ไม่มีตัวเลือกที่สามที่นี่
มาร์ควิสแห่ง Lorne

1
และ upvote สำหรับตัวอย่างของ COBOL ทำให้ฉันดีใจยิ่งกว่าที่ COBOL ส่วนใหญ่เสียชีวิตก่อนที่ฉันจะได้รับการเข้ารหัส
Mark K Cowan

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

2

ดังที่กล่าวไว้ในบางคำตอบที่มีอยู่ (ซึ่งน่ารำคาญฉันไม่สามารถแสดงความคิดเห็นใน), ปัญหาคือ x ++ ++ x ประเมินค่าที่แตกต่างกัน (ก่อน vs หลังจากเพิ่มขึ้น) ซึ่งไม่ชัดเจนและอาจสับสนมาก - ถ้าใช้ค่านั้น cdmckay แนะนำให้ใช้ตัวดำเนินการเพิ่มอย่างชาญฉลาด แต่ในทางที่ไม่ได้ใช้ค่าที่ส่งคืนเช่นในบรรทัดของตัวเอง ฉันจะรวมถึงการใช้มาตรฐานภายในวงสำหรับ (แต่เฉพาะในคำสั่งที่สามซึ่งไม่ได้ใช้ค่าส่งคืน) ฉันไม่สามารถคิดถึงตัวอย่างอื่นได้ เมื่อถูก "เผา" ตัวเองฉันจะแนะนำแนวทางเดียวกันสำหรับภาษาอื่นเช่นกัน

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


1
ขอบคุณสำหรับการตอบกลับ. คุณจะต้องมีค่าชื่อเสียง 50 หรือดีกว่าเพื่อแสดงความคิดเห็น ดู: stackoverflow.com/faq
artlung

1
@artlung: ฉันรู้ว่าและเหตุผลที่อยู่เบื้องหลัง ฉันแค่บอกว่ามันน่ารำคาญ :)
ใกล้ Privman

2

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

while ( a < 10 ){
    array[a++] = val
}

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

นอกจากนี้ Crockford ดูเหมือนว่าจะใช้ i- = 1 ซึ่งฉันคิดว่าอ่านยากกว่า --i หรือ i -


2

2cents ของฉันคือพวกเขาควรหลีกเลี่ยงในสองกรณี:

1) เมื่อคุณมีตัวแปรที่ใช้ในหลาย ๆ แถวและคุณเพิ่ม / ลดลงในคำสั่งแรกที่ใช้มัน (หรือสุดท้ายหรือแย่กว่านั้นคือตรงกลาง):

// It's Java, but applies to Js too
vi = list.get ( ++i );
vi1 = list.get ( i + 1 )
out.println ( "Processing values: " + vi + ", " + vi1 )
if ( i < list.size () - 1 ) ...

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

2) ในกรณีที่มีหลาย ++ และ - เกี่ยวกับตัวแปรเดียวกันในคำสั่งเดียวกัน มันยากมากที่จะจำสิ่งที่เกิดขึ้นในกรณีเช่นนี้:

result = ( ++x - --x ) * x++;

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


1

Fortran เป็นภาษา C หรือไม่ มันไม่มีทั้ง ++ และ - นี่คือวิธีที่คุณเขียนลูป :

     integer i, n, sum

      sum = 0
      do 10 i = 1, n
         sum = sum + i
         write(*,*) 'i =', i
         write(*,*) 'sum =', sum
  10  continue

องค์ประกอบดัชนีiถูกเพิ่มค่าโดยกฎภาษาในแต่ละครั้งที่วนซ้ำ หากคุณต้องการเพิ่มด้วยค่าอื่นที่ไม่ใช่ 1 ให้นับถอยหลังเป็นสองตัวอย่างเช่นไวยากรณ์คือ ...

      integer i

      do 20 i = 10, 1, -2
         write(*,*) 'i =', i
  20  continue

Python C เป็นแบบไหน? มันใช้ช่วงและรายการความเข้าใจและไวยากรณ์อื่น ๆ เพื่อหลีกเลี่ยงความจำเป็นในการเพิ่มดัชนี:

print range(10,1,-2) # prints [10,8.6.4.2]
[x*x for x in range(1,10)] # returns [1,4,9,16 ... ]

ดังนั้นจากการสำรวจขั้นพื้นฐานของทางเลือกสองทางนี้นักออกแบบภาษาอาจหลีกเลี่ยง ++ และ - โดยการคาดการณ์กรณีการใช้งานและการจัดเตรียมไวยากรณ์ทางเลือก

Fortran และ Python มีข้อผิดพลาดน้อยกว่าภาษาเชิงโพรซีเดอร์ที่มี ++ และ - หรือไม่? ฉันไม่มีหลักฐาน

ฉันอ้างว่า Fortran และ Python เหมือน C เพราะฉันไม่เคยพบใครบางคนใน C ที่ไม่สามารถแม่นยำ 90% เดาได้อย่างถูกต้องว่าเจตนาของ Fortran หรือ Python ที่ไม่ทำให้สับสน


1
ใช่ IFortran มาจากปี 1950 ในขณะที่ C มาจากปี 1970 ดังนั้นอาจไม่มี Fortran ที่เป็นแบบ C ตัวอย่างของ Python ที่ไม่มีบางอย่างเช่นเครื่องหมายบวกเป็นสิ่งที่น่าสนใจ การทำซ้ำโครงสร้างข้อมูลจะถูกจัดการอย่างชัดเจนมากขึ้นใน Python และ Python เป็นจาวาสคริปต์ที่ "แตกต่าง" ในเชิงวัตถุ บางทีคำแนะนำของ Crockford นั้นเกี่ยวกับการใช้ไวยากรณ์ที่คล้ายกับ OO มากขึ้นสำหรับการวนซ้ำ
artlung
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.