ทำไม setters ที่ไม่เป็นทางการคืออะไร


46

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

public class DTO {

    private String foo;
    private String bar;

    public String getFoo() {
         return foo;
    }

    public String getBar() {
        return bar;
    }

    public DTO setFoo(String foo) {
        this.foo = foo;
        return this;
    }

    public DTO setBar(String bar) {
        this.bar = bar;
        return this;
    }

}

//...//

DTO dto = new DTO().setFoo("foo").setBar("bar");

32
เนื่องจาก Java อาจเป็นภาษาเดียวที่ตัวตั้งค่าไม่ใช่สิ่งที่น่ารังเกียจสำหรับมนุษย์ ...
Telastyn

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

58
รูปแบบนี้ไม่ใช่เรื่องแปลกเลย มีแม้กระทั่งชื่อของมัน มันเรียกว่าอินเตอร์เฟซได้อย่างคล่องแคล่ว
ฟิลิปป์

9
นอกจากนี้คุณยังสามารถสรุปการสร้างนี้ในเครื่องมือสร้างเพื่อให้ได้ผลลัพธ์ที่อ่านง่ายขึ้น myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();ฉันทำอย่างนั้นเพื่อที่จะไม่ขัดแย้งกับแนวคิดทั่วไปที่ผู้ตั้งค่าเป็นช่องว่าง

9
@ ฟิลิปป์ในขณะที่คุณพูดถูกเทคนิคจะไม่พูดว่าnew Foo().setBar('bar').setBaz('baz')รู้สึก "คล่องแคล่ว" มาก ฉันหมายถึงแน่ใจว่ามันสามารถใช้งานได้ในลักษณะเดียวกัน แต่ฉันคาดหวังอย่างมากว่าจะอ่านอะไรเพิ่มเติมFoo().barsThe('bar').withThe('baz').andQuuxes('the quux')
Wayne Werner

คำตอบ:


50

ดังนั้นมีเหตุผลทำไมนี่ไม่ใช่การประชุม OOP

การเดาที่ดีที่สุดของฉัน: เพราะมันละเมิดCQS

คุณได้รับคำสั่ง (เปลี่ยนสถานะของวัตถุ) และแบบสอบถาม (คืนสำเนาของรัฐ - ในกรณีนี้วัตถุเอง) ผสมกันเป็นวิธีเดียวกัน ไม่จำเป็นต้องเป็นปัญหา แต่มันละเมิดหลักเกณฑ์พื้นฐานบางประการ

ตัวอย่างเช่นใน C ++, std :: stack :: pop () เป็นคำสั่งที่ส่งกลับค่าโมฆะและ std :: stack :: top () เป็นแบบสอบถามที่ส่งคืนการอ้างอิงไปยังองค์ประกอบด้านบนในสแต็ก คลาสสิกคุณต้องการรวมทั้งสองอย่างเข้าด้วยกัน แต่คุณไม่สามารถทำได้และปลอดภัยยกเว้น (ไม่ใช่ปัญหาใน Java เนื่องจากตัวดำเนินการกำหนดค่าใน Java ไม่ได้โยน)

หาก DTO เป็นประเภทค่าคุณอาจได้รับจุดสิ้นสุดที่คล้ายกัน

public DTO setFoo(String foo) {
    return new DTO(foo, this.bar);
}

public DTO setBar(String bar) {
    return new DTO(this.foo, bar);
}

นอกจากนี้ค่าตอบแทนที่ผูกมัดเป็นความเจ็บปวดมหึมาเมื่อคุณกำลังจัดการกับมรดก ดู"รูปแบบเทมเพลตที่เกิดซ้ำซอกแซก"

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


4
ในที่สุด catain ที่นี่จริง การสืบทอดเป็นปัญหาที่แท้จริง ฉันคิดว่าการผูกมัดอาจเป็น setter ทั่วไปสำหรับการแสดงข้อมูลวัตถุที่ใช้ในการจัดองค์ประกอบ
เบ็น

6
"ส่งคืนสำเนาสถานะจากวัตถุ" - ไม่ทำเช่นนั้น
user253751

2
ฉันจะยืนยันว่าเหตุผลที่ดีที่สุดสำหรับการปฏิบัติตามแนวทางเหล่านั้น (มีข้อยกเว้นที่น่าสังเกตบางอย่างเช่นตัววนซ้ำ) คือการทำให้โค้ดง่ายขึ้นอย่างมากมายที่จะให้เหตุผล
jpmc26

1
@MatthieuM Nope ฉันพูดภาษาจาวาเป็นหลักและเป็นที่แพร่หลายใน API "fluid" ขั้นสูง - ฉันแน่ใจว่ามันมีอยู่ในภาษาอื่น เป็นหลักคุณทำให้ประเภททั่วไปในประเภทขยายตัวเอง จากนั้นคุณจะเพิ่มabstract T getSelf()วิธีที่คืนประเภททั่วไป ตอนนี้แทนที่จะกลับthisจาก setters คุณreturn getSelf()แล้วชั้นเอาชนะใด ๆ ก็ทำให้ประเภททั่วไปในตัวเองและผลตอบแทนจากthis getSelfวิธีนี้ผู้ตั้งค่าส่งคืนชนิดจริงไม่ใช่ประเภทประกาศ
Boris the Spider

1
@MatthieuM จริงๆ? เสียงคล้ายกับ CRTP สำหรับ C ++ ...
ไม่มีประโยชน์

33
  1. การบันทึกการกดแป้นบางอย่างนั้นไม่น่าสนใจ มันอาจจะดี แต่การประชุม OOP ให้ความสำคัญกับแนวคิดและโครงสร้างไม่ใช่การกดแป้น

  2. ค่าส่งคืนนั้นไม่มีความหมาย

  3. ยิ่งกว่าไร้ความหมายค่าส่งคืนนั้นทำให้เข้าใจผิดเนื่องจากผู้ใช้อาจคาดหวังว่าค่าที่ส่งคืนจะมีความหมาย พวกเขาอาจคาดหวังว่ามันเป็น "หมาตัวเซ็ทที่ไม่เปลี่ยนรูป"

    public FooHolder {
        public FooHolder withFoo(int foo) {
            /* return a modified COPY of this FooHolder instance */
        }
    }
    

    ในความเป็นจริง setter ของคุณกลายพันธุ์วัตถุ

  4. มันใช้งานไม่ได้กับมรดก

    public FooHolder {
        public FooHolder setFoo(int foo) {
            ...
        }
    }
    
    public BarHolder extends FooHolder {
        public FooHolder setBar(int bar) {
            ...
        }
    } 
    

    ฉันเขียนได้

    new BarHolder().setBar(2).setFoo(1)

    แต่ไม่

    new BarHolder().setFoo(1).setBar(2)

สำหรับฉัน # 1 ถึง # 3 เป็นคนสำคัญ โค้ดที่เขียนได้ดีนั้นไม่เกี่ยวกับข้อความที่จัดเรียงอย่างน่าพึงพอใจ รหัสที่เขียนได้ดีนั้นเกี่ยวกับแนวคิดพื้นฐานความสัมพันธ์และโครงสร้าง ข้อความเป็นเพียงภาพสะท้อนภายนอกของความหมายที่แท้จริงของโค้ด


2
แม้ว่าข้อโต้แย้งเหล่านี้ส่วนใหญ่จะใช้กับอินเทอร์เฟซที่ใช้งานได้ / เชื่อมต่อได้
Casey

@Casey ใช่ ผู้สร้าง (เช่นกับ setters) เป็นกรณีส่วนใหญ่ที่ฉันเห็นของการผูกมัด
พอลเดรเปอร์

10
หากคุณคุ้นเคยกับแนวคิดของอินเทอร์เฟซที่คล่องแคล่ว # 3 ไม่สามารถใช้งานได้เนื่องจากคุณมีแนวโน้มที่จะสงสัยว่าอินเทอร์เฟซที่คล่องแคล่วจากประเภทการส่งคืน ฉันต้องไม่เห็นด้วยกับ "รหัสที่เขียนดีไม่เกี่ยวกับข้อความที่จัดเรียงอย่างเป็นสุข" นั่นไม่ใช่ทั้งหมดที่เกี่ยวกับ แต่การจัดเรียงข้อความเป็นสิ่งที่ค่อนข้างสำคัญเนื่องจากช่วยให้ผู้อ่านโปรแกรมสามารถเข้าใจได้โดยใช้ความพยายามน้อยลง
Michael Shaw

1
Setter chaining ไม่ได้เกี่ยวกับการจัดเรียงข้อความหรือเกี่ยวกับการบันทึกการกดแป้น มันเกี่ยวกับการลดจำนวนตัวระบุ ด้วย setter chaining คุณสามารถสร้างและตั้งค่าออบเจกต์ในนิพจน์เดียวซึ่งหมายความว่าคุณอาจไม่ต้องบันทึกมันในตัวแปร - ตัวแปรที่คุณต้องตั้งชื่อและจะอยู่ที่นั่นจนกว่าจะสิ้นสุดขอบเขต
Idan Arye

3
เกี่ยวกับจุด # 4 มันเป็นสิ่งที่สามารถแก้ไขได้ใน Java ดังนี้กับหมากลับpublic class Foo<T extends Foo> {...} Foo<T>ด้วยวิธีการ 'setter' เหล่านั้นฉันชอบที่จะเรียกพวกเขาด้วยวิธีการ หากการบรรทุกเกินพิกัดทำงานได้ดีแสดงว่าไม่Foo<T> with(Bar b) {...}เป็นเช่นFoo<T> withBar(Bar b)นั้น
YoYo

12

ฉันไม่คิดว่านี่เป็นแบบแผนของ OOP มันเกี่ยวข้องกับการออกแบบภาษาและแบบแผนมากกว่า

ดูเหมือนว่าคุณต้องการใช้ Java Java มีข้อกำหนดJavaBeansซึ่งระบุชนิดการคืนค่าของ setter ให้เป็นโมฆะนั่นคือขัดแย้งกับการโยงของ setters ข้อมูลจำเพาะนี้ได้รับการยอมรับและนำไปใช้อย่างแพร่หลายในเครื่องมือที่หลากหลาย

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


ใช่ JavaBeans เป็นสิ่งที่ฉันมีอยู่ในใจ
เบ็น

ฉันไม่คิดว่าแอปพลิเคชันส่วนใหญ่ที่ใช้ JavaBeans สนใจ แต่พวกเขาอาจ (ใช้การสะท้อนเพื่อคว้าวิธีที่มีชื่อว่า 'set ... ' มีพารามิเตอร์เดียวและเป็นโมฆะคืน ) โปรแกรมการวิเคราะห์สแตติกจำนวนมากบ่นว่าไม่ได้ตรวจสอบค่าส่งคืนจากวิธีที่คืนค่าบางอย่างซึ่งอาจน่ารำคาญมาก

@MichaelT การเรียกไตร่ตรองเพื่อรับเมธอดใน Java ไม่ได้ระบุชนิดการส่งคืน การเรียกใช้เมธอดที่ส่งคืนObjectซึ่งอาจส่งผลให้ชนิดซิงเกิลตันVoidถูกส่งคืนหากเมธอดระบุvoidว่าเป็นชนิดส่งคืน ในข่าวอื่น ๆ เห็นได้ชัดว่า "การแสดงความคิดเห็น แต่ไม่ได้ลงคะแนน" เป็นเหตุให้การตรวจสอบ "โพสต์แรก" ล้มเหลวแม้ว่าจะเป็นความคิดเห็นที่ดีก็ตาม ฉันตำหนิโชกสำหรับเรื่องนี้

7

ขณะที่คนอื่น ๆ ได้กล่าวมานี้มักจะเรียกว่าอินเตอร์เฟซได้อย่างคล่องแคล่ว

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

อย่างไรก็ตามมีบางกรณีที่อินเตอร์เฟซที่คล่องแคล่วอาจเป็นทางออกที่ดีสิ่งเหล่านี้มีเหมือนกัน

  • ค่าคงที่ส่วนใหญ่จะถูกส่งไปยังผู้ตั้งค่า
  • ตรรกะของโปรแกรมจะไม่เปลี่ยนแปลงสิ่งที่ผ่านไปยังตัวตั้งค่า

การตั้งค่าคอนฟิเกอเรชันเช่นfluent-nhibernate

Id(x => x.Id);
Map(x => x.Name)
   .Length(16)
   .Not.Nullable();
HasMany(x => x.Staff)
   .Inverse()
   .Cascade.All();
HasManyToMany(x => x.Products)
   .Cascade.All()
   .Table("StoreProduct");

การตั้งค่าข้อมูลการทดสอบในการทดสอบหน่วยโดยใช้TestDataBulderClassesพิเศษ(Object Mothers)

members = MemberBuilder.CreateList(4)
    .TheFirst(1).With(b => b.WithFirstName("Rob"))
    .TheNext(2).With(b => b.WithFirstName("Poya"))
    .TheNext(1).With(b => b.WithFirstName("Matt"))
    .BuildList(); // Note the "build" method sets everything else to
                  // senible default values so a test only need to define 
                  // what it care about, even if for example a member 
                  // MUST have MembershipId  set

อย่างไรก็ตามการสร้างส่วนต่อประสานที่ดีนั้นทำได้ยากมากดังนั้นมันจึงคุ้มค่าเมื่อคุณมีการตั้งค่า "คงที่" จำนวนมาก อินเทอร์เฟซที่คล่องแคล่วไม่ควรผสมกับคลาส "ปกติ" ดังนั้นรูปแบบการสร้างมักจะใช้


5

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

แทน:

DTO dto = new DTO().setFoo("foo").setBar("bar");

หนึ่งอาจเขียน:

(ใน JS)

var dto = new DTO({foo: "foo", bar: "bar"});

(ใน C #)

DTO dto = new DTO{Foo = "foo", Bar = "bar"};

(ใน Java)

DTO dto = new DTO("foo", "bar");

setFooและsetBarไม่จำเป็นสำหรับการเริ่มต้นอีกต่อไปและสามารถใช้สำหรับการกลายพันธุ์ในภายหลัง

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

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

dto.setFoo("foo").setBar("fizz").setFizz("bar").setBuzz("buzz");

ทำให้ยากต่อการอ่านและเข้าใจสิ่งที่เกิดขึ้น การจัดรูปแบบใหม่เป็น:

dto.setFoo("foo")
    .setBar("fizz")
    .setFizz("bar")
    .setBuzz("buzz");

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

dto.setFoo("foo");
dto.setBar("bar");
dto.setFizz("fizz");
dto.setBuzz("buzz");

3
1. ฉันไม่เห็นด้วยกับปัญหาการอ่านการเพิ่มอินสแตนซ์ก่อนการโทรแต่ละครั้งจะไม่ทำให้ชัดเจนขึ้น 2. รูปแบบการเริ่มต้นที่คุณแสดงด้วย js และ C # ไม่มีส่วนเกี่ยวข้องกับตัวสร้าง: สิ่งที่คุณทำใน js นั้นผ่านการโต้แย้งเดียวและสิ่งที่คุณทำใน C # คือ shugar ไวยากรณ์ที่เรียก geters และ setters เบื้องหลังและ java ไม่มี shugar geter-setter เหมือน C #
เบ็น

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

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

1
VB.NET นอกจากนี้ยังมีใช้งานได้ "กับ" คำหลักที่สร้างอ้างอิงคอมไพเลอร์ชั่วคราวเพื่อให้เช่น [ใช้/เพื่อแสดงให้เห็นถึงเส้นแบ่ง] จะเทียบเท่ากับWith Foo(1234) / .x = 23 / .y = 47 Dim temp=Foo(1234) / temp.x = 23 / temp.y = 47ไวยากรณ์ดังกล่าวไม่ได้สร้างความกำกวมเนื่องจาก.xตัวมันเองจะไม่มีความหมายอื่นใดนอกจากผูกติดกับคำสั่ง "ด้วย" ในทันที [ถ้าไม่มีหรือวัตถุไม่มีสมาชิกxก็.xไม่มีความหมาย] Oracle ไม่ได้รวมอะไรเช่นนั้นไว้ใน Java แต่โครงสร้างดังกล่าวจะพอดีกับภาษาอย่างราบรื่น
supercat

5

เทคนิคนั้นใช้จริงในรูปแบบตัวสร้าง

x = ObjectBuilder()
        .foo(5)
        .bar(6);

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


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

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

@ JAB ฉันเห็นด้วยฉันไม่ได้เป็นแฟนของสัญกรณ์นั้น แต่มีสถานที่ สิ่งที่อยู่ในใจคือObj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3)); ฉันคิดว่ามันได้รับความนิยมเพราะมันสะท้อนa = b = c = dถึงแม้ว่าฉันจะไม่เชื่อว่าความนิยมนั้นได้รับการพิสูจน์แล้ว ฉันเห็นสิ่งที่คุณพูดถึงคืนค่าก่อนหน้าในห้องสมุดปฏิบัติการปรมาณู นิทานสอนใจ? มันยิ่งทำให้สับสนมากกว่าที่ฉันบอกไว้ว่าเสียง)
Cort Ammon

ฉันเชื่อว่านักวิชาการมีอวดรู้เล็กน้อย: ไม่มีอะไรผิดปกติกับสำนวน มันมีประโยชน์อย่างมากในการเพิ่มความชัดเจนในบางกรณี ใช้ข้อความต่อไปนี้การจัดรูปแบบชั้นเรียนสำหรับตัวอย่างที่เพิ่ม Tab บรรทัดของสตริงทุกและดึงกล่อง new BetterText(string).indent(4).box().print();ascii-ศิลปะรอบ ในกรณีนั้นฉันได้ข้าม gobbledygook ไปเป็นมัด ๆ แล้วนำสตริงเยื้องใส่กล่องแล้วส่งออกไป คุณอาจต้องการวิธีการทำซ้ำภายในการเรียงซ้อน (เช่นพูด.copy()) เพื่อให้การกระทำต่อไปนี้ทั้งหมดไม่แก้ไขต้นฉบับอีกต่อไป
tgm1024

2

นี่เป็นความคิดเห็นมากกว่าคำตอบ แต่ฉันไม่สามารถแสดงความคิดเห็นดังนั้น ...

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

ตัวอย่างเช่นนี้เป็นวิธีที่ Symfony ของหลักคำสอน: สร้าง: หน่วยงานคำสั่งอัตโนมัติสร้างทั้งหมด setters , โดยปริยาย

jQuery kindaโซ่วิธีส่วนใหญ่ในลักษณะที่คล้ายกันมาก


Js เป็นสิ่งที่น่ารังเกียจ
เบ็น

@ เบเนดิคฉันจะบอกว่า PHP เป็นสิ่งที่น่ารังเกียจยิ่งใหญ่ JavaScript เป็นภาษาที่ดีมากและได้ค่อนข้างดีด้วยการรวมคุณสมบัติ ES6 (แม้ว่าฉันแน่ใจว่าบางคนยังคงชอบ CoffeeScript หรือตัวแปร) โดยส่วนตัวฉันไม่ใช่แฟนตัวยงของ CoffeeScript ที่จัดการขอบเขตการกำหนดตัวแปรเนื่องจากตรวจสอบขอบเขตด้านนอก อันดับแรกแทนที่จะจัดการกับตัวแปรที่กำหนดให้ในขอบเขตท้องถิ่นเป็นท้องถิ่นเว้นแต่ระบุไว้อย่างชัดเจนว่าไม่ใช่ท้องถิ่น / ทั่วโลกในแบบที่ Python ทำ)
JAB

@Benedictus JABฉันไม่ขัดข้องกับ ในปีที่วิทยาลัยของฉันฉันเคยดูถูก JS เป็นภาษาที่น่ารังเกียจอยากเป็นสคริปต์ แต่หลังจากทำงานสองสามปีกับมันและเรียนรู้วิธีที่ถูกต้องในการใช้มันฉันมา ... รักมันจริงๆ. และฉันคิดว่าด้วย ES6 มันจะกลายเป็นภาษาที่โตเต็มที่ แต่สิ่งที่ทำให้ฉันหันหัวของฉันคือ ... คำตอบของฉันเกี่ยวข้องกับ JS ในตอนแรก? ^^ U
xDaizu

จริง ๆ แล้วฉันทำงานกับ js สองสามปีและสามารถพูดได้ว่าฉันได้เรียนรู้วิธีการแล้ว อย่างไรก็ตามฉันเห็นว่าภาษานี้ไม่มีอะไรมากไปกว่าความผิดพลาด แต่ฉันเห็นด้วย php แย่ลงมาก
เบ็น

@ Benedictus ฉันเข้าใจตำแหน่งของคุณและฉันเคารพมัน ฉันยังคงชอบมัน แน่นอนว่ามันมีนิสัยใจคอและความชอบ (ภาษาใดไม่ได้) แต่มันก็ก้าวไปในทิศทางที่ถูกต้อง แต่ ... ฉันไม่ชอบมันมากจนต้องปกป้องมัน ฉันไม่ได้อะไรจากคนที่รักหรือเกลียดมัน ... ฮ่าฮ่าฮ่านอกจากนี้ที่นี่ยังไม่มีที่สำหรับคำตอบของฉันไม่ได้เกี่ยวกับ JS เลย
xDaizu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.