วิธีการเทียบกับคำนวณใน Vue


178

ความแตกต่างที่สำคัญระหว่างวิธีการและค่าที่คำนวณใน Vue.js คืออะไร?

พวกเขามีลักษณะเหมือนกันและใช้แทนกันได้


อาจเป็นประโยชน์สำหรับคุณ: vuejs.org/v2/guide/computed.html#Computed-Properties
DunDev

1
@xDreamCoding คำตอบที่คุณเชื่อมโยงเกิดขึ้นกับคำถามนี้แน่นอน แต่คำถามนี้ไม่เหมือนกัน รวมทั้งมีชื่อเสียงมากขึ้น
Romain Vincent

อ้างถึงเอกสารประกอบซึ่งมีแสงสว่างในหัวข้อนี้ภายใต้หัวข้อคุณสมบัติที่คำนวณกับวิธีการ: vuejs.org/v2/guide/computed.html
Kshitij Dhyani

คำตอบ:


243

ค่าและวิธีการคำนวณแตกต่างกันมากใน Vue และไม่สามารถใช้แทนกันได้ในกรณีส่วนใหญ่

คำนวณทรัพย์สิน

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

computed: {
  // a computed getter
  reversedMessage: function () {
    // `this` points to the vm instance
    return this.message.split('').reverse().join('')
  }
}

ซึ่งมีการอ้างอิงใน DOM เช่นนี้:

<p>Computed reversed message: "{{ reversedMessage }}"</p>

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

data:{
    names: ["Bob", "Billy", "Mary", "Jane"]
},
computed:{
    startsWithB(){
        return this.names.filter(n => n.startsWith("B"))
    }
}

<p v-for="name in startsWithB">{{name}}</p>

ค่าที่คำนวณจะถูกเก็บไว้ในแคชเพื่อหลีกเลี่ยงการคำนวณซ้ำซึ่งไม่จำเป็นต้องคำนวณซ้ำเมื่อไม่มีการเปลี่ยนแปลง (เช่นอาจไม่อยู่ในวงวน)

วิธี

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

data:{
    names: ["Bob", "Billy", "Mary", "Jane"]
},
computed:{
    startsWithB(){
        return this.startsWithChar("B")
    },
    startsWithM(){
        return this.startsWithChar("M")
    }
},
methods:{
    startsWithChar(whichChar){
        return this.names.filter(n => n.startsWith(whichCharacter))
    }
}

เอกสารของ Vue นั้นดีและสามารถเข้าถึงได้ง่าย ฉันแนะนำมัน


1
หากมีสองอินพุตจากผู้ใช้เช่นการแปลงอุณหภูมิจาก c เป็น f และในทางกลับกันซึ่งอินพุตทั้งสองสามารถกำหนดค่าซึ่งกันและกัน ดูalbireo.ch/temperatureconverterและอินพุตทั้งสองตอบสนองโดยอัตโนมัติโดยไม่ต้องกดปุ่มแปลง แบบไหนดีที่สุดที่จะใช้วิธีการคำนวณหรือ?
Bootstrap4

2
ด้วยUI ที่เฉพาะเจาะจงที่ซึ่งมีความสัมพันธ์แบบวงกลมระหว่างอินพุตฉันจะใช้วิธีต่างๆ codepen.io/Kradek/pen/gROQeB?editors=1010
Bert

2
@ Bootstrap4 ถึงแม้ว่าที่นี่เป็นสิ่งหนึ่งที่มีการคำนวณเช่นกัน แต่มันมีความซับซ้อนมากกว่า codepen.io/Kradek/pen/gROQeB?editors=1010
Bert

3
> วิธีการ ... จะได้รับการประเมินเมื่อคุณเรียกอย่างชัดเจนเท่านั้น ไม่เป็นไปตามวิดีโอนี้: youtube.com/watch?v=O14qJr5sKXo
Cameron Hudson

2
@CameronHudson ในตัวอย่างในวิดีโอ, วิธีการที่จะมีการประเมินเพราะพวกเขามีการอ้างอิงอย่างชัดเจนในแม่แบบ นี่คือตัวอย่างที่แสดงให้เห็นความแตกต่างได้ โปรดทราบว่าวิธีการนั้นจะถูกเรียกใช้เฉพาะเมื่อข้อมูลเปลี่ยนแปลงหากมีการอ้างอิงอย่างชัดเจนในเทมเพลต
Bert

60

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

app.js

new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },
    methods: {
        addToAmethod: function(){
            console.log('addToAmethod');
            return this.a + this.age;
        },
        addToBmethod: function(){
            console.log('addToBmethod');
            return this.b + this.age;
        }
    },
    computed: {
        addToAcomputed: function(){
            console.log('addToAcomputed');
            return this.a + this.age;
        },
        addToBcomputed: function(){
            console.log('addToBcomputed');
            return this.b + this.age;
        }
    }
});

ที่นี่เรามี 2 วิธีและ 2 คุณสมบัติที่คำนวณได้ซึ่งทำหน้าที่เดียวกัน วิธีการaddToAmethodและaddToBmethodและคุณสมบัติคำนวณaddToAcomputedและaddToBcomputedเพิ่ม +20 (เช่นทุกageค่า) อย่างใดอย่างหนึ่งหรือa bเกี่ยวกับวิธีการพวกเขาทั้งคู่ถูกเรียกทุกครั้งที่มีการดำเนินการใด ๆที่ระบุไว้แม้ว่าการพึ่งพาสำหรับวิธีการหนึ่งโดยเฉพาะจะไม่เปลี่ยนแปลง สำหรับคุณสมบัติที่คำนวณรหัสจะถูกดำเนินการเฉพาะเมื่อมีการเปลี่ยนแปลงการอ้างอิง; ตัวอย่างเช่นหนึ่งในค่าคุณสมบัติเฉพาะที่อ้างถึง A หรือ B จะทริกเกอร์addToAcomputedหรือaddToBcomputedตามลำดับ

วิธีการและคำอธิบายที่คำนวณได้ดูเหมือนคล้ายกันมาก แต่เนื่องจาก @Abdullah Khan มีอยู่แล้ว ที่ระบุว่าพวกเขาไม่ได้ในสิ่งเดียวกัน ! ตอนนี้ลองเพิ่ม html เพื่อดำเนินการทุกอย่างเข้าด้วยกันและดูความแตกต่าง

ตัวอย่างกรณีวิธี

new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },
    methods: {
        addToAmethod: function(){
            console.log('addToAmethod');
            return this.a + this.age;
        },
        addToBmethod: function(){
            console.log('addToBmethod');
            return this.b + this.age;
        }
    }
});
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>VueJS Methods - stackoverflow</title>
            <link href="style.css" rel="stylesheet" />
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
    
        </head>
        <body>
            <div id="vue-app">
                <h1>Methods</h1>
                <button v-on:click="a++">Add to A</button>
                <button v-on:click="b++">Add to B</button>
                <p>Age + A = {{ addToAmethod() }}</p>
                <p>Age + B = {{ addToBmethod() }}</p>
            </div>
        </body>
        
        <script src="app.js"></script>
    </html>

ผลการอธิบาย

เมื่อฉันคลิกที่ปุ่ม"เพิ่มไปยัง A"วิธีการทั้งหมดจะถูกเรียก (ดูผลหน้าจอบันทึกคอนโซลข้างต้น) addToBmethod()จะถูกดำเนินการด้วย แต่ฉันไม่ได้กดปุ่ม"เพิ่มไปยัง B" ; มูลค่าทรัพย์สินที่อ้างถึง B ไม่เปลี่ยนแปลง พฤติกรรมเดียวกันนี้เกิดขึ้นถ้าเราตัดสินใจคลิกปุ่ม"เพิ่มลงใน B"เพราะทั้งสองวิธีจะถูกเรียกอย่างอิสระจากการเปลี่ยนแปลงการพึ่งพา ตามสถานการณ์สมมตินี้เป็นการปฏิบัติที่ไม่ถูกต้องเนื่องจากเรากำลังดำเนินการวิธีการทุกครั้งแม้ว่าการอ้างอิงจะไม่เปลี่ยนแปลง สิ่งนี้เป็นการสิ้นเปลืองทรัพยากรจริงๆเพราะไม่มีแคชสำหรับค่าคุณสมบัติที่ไม่เปลี่ยนแปลง

วิธี วิธีการปุ่ม

ตัวอย่างการคำนวณคุณสมบัติเคส

new Vue({
    el: '#vue-app',
    data: {
        a: 0,
        b: 0,
        age: 20
    },

    computed: {
        addToAcomputed: function(){
            console.log('addToAcomputed');
            return this.a + this.age;
        },
        addToBcomputed: function(){
            console.log('addToBcomputed');
            return this.b + this.age;
        }
    }
});
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>VueJS Computed properties - stackoverflow</title>
            <link href="style.css" rel="stylesheet" />
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>
        </head>
        <body>
            <div id="vue-app">
                <h1>Computed Properties</h1>
                <button v-on:click="a++">Add to A</button>
                <button v-on:click="b++">Add to B</button>
                <p>Age + A = {{ addToAcomputed }}</p>
                <p>Age + B = {{ addToBcomputed }}</p>
            </div>
        </body>
        
        <script src="app.js"></script>
    </html>

ผลการอธิบาย

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

คำนวณ คำนวณปุ่มแล้ว


3
ทำไมวิธีการทั้งหมดถึงถูกเรียกใช้งานเมื่อกด 1 ปุ่ม เหตุผล / ตรรกะคืออะไร
Bsienn

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

2
และอะไรคือสาเหตุของการใช้วิธีการ? ดูเหมือนว่าคุณสมบัติที่คำนวณได้จะดีกว่า (สมมติว่าเรากำลังพูดถึงวิธีการ 'รับ') ...
user3529607

5
@ user3529607 แต่คุณสมบัติที่คำนวณแล้วจะไม่ได้รับอาร์กิวเมนต์
Rodion Golovushkin

3
@ user3529607 จากสิ่งที่ฉันสามารถเข้าใจได้วิธีการจะมีประโยชน์ขณะติดตั้งหรือสร้างอินสแตนซ์ของ vue เดียวกันไม่สามารถทำได้ด้วยคุณสมบัติที่คำนวณได้ นอกจากนี้เราต้องส่งคืนค่าสำหรับคุณสมบัติที่คำนวณได้
Dhaval Chheda

13

จาก docs

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

ถ้าคุณต้องการให้ข้อมูลถูกแคชใช้คุณสมบัติที่คำนวณได้ในทางกลับกันถ้าคุณไม่ต้องการให้ข้อมูลถูกแคชให้ใช้คุณสมบัติวิธีการอย่างง่าย


1
สวัสดีคุณช่วยเขียนตัวอย่างที่มีประโยชน์เพื่อแสดงความแตกต่างระหว่างการใช้งานจริงได้หรือไม่?
Davide De Maestri

@gleenk ฉันจะเพิ่มตัวอย่างการปฏิบัติเพื่อแสดงให้คุณเห็นความแตกต่างแคช / การอ้างอิงระหว่างวิธีการและคุณสมบัติที่คำนวณได้ ฉันหวังว่าคุณจะประทับใจ
Giulio Bambini

ขอบคุณ @GiulioBambini
Davide De Maestri

7

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

คอมพิวเตอร์

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

วิธี

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

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


6

นี่คือรายละเอียดของคำถามนี้

ควรใช้วิธีการเมื่อใด

  • เพื่อตอบสนองต่อเหตุการณ์บางอย่างที่เกิดขึ้นใน DOM
  • เมื่อต้องการเรียกใช้ฟังก์ชันเมื่อมีบางสิ่งเกิดขึ้นในส่วนประกอบของคุณ
  • คุณสามารถเรียกวิธีการจากคุณสมบัติที่คำนวณได้หรือผู้เฝ้าดู

เมื่อใดจึงจะใช้คุณสมบัติที่คำนวณได้

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

2

คุณสมบัติที่คำนวณได้

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

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

วิธีการ

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

ในวิธีการเรียกวงเล็บคือมีและคุณสามารถส่งหนึ่งพารามิเตอร์หรือมากกว่านั้น


0

สะดุดกับคำถามเดียวกัน สำหรับฉันมันชัดเจนมากขึ้นเช่นนี้:

  1. เมื่อ Vue.js เห็นวิธีv-on directiveตามด้วยวิธีนั้นจะรู้ได้อย่างชัดเจนว่าวิธีใดในการโทรและเวลาที่จะเรียก
<button v-on:click="clearMessage">Clear message</button> // @click
// method clearMessage is only called on a click on this button

<input v-model="message" @keyup.esc="clearMessage" @keyup.enter="alertMessage" />
/* The method clearMessage is only called on pressing the escape key
and the alertMessage method on pressing the enter key */
  1. เมื่อวิธีการถูกเรียกโดยไม่มีv-on directiveมันจะถูกเรียกทุกครั้งที่มีเหตุการณ์ที่เกิดขึ้นบนหน้าเว็บที่อัปเดต DOM (หรือเพียงแค่ต้องแสดงอีกส่วนหนึ่งของหน้า) แม้ว่าวิธีการนั้นจะไม่เกี่ยวข้องกับเหตุการณ์ที่เกิดขึ้น
<p>Uppercase message: {{ messageUppercase() }}</p>
methods: {
   messageUppercase() {
      console.log("messageUpercase");
      return this.message.toUpperCase();
   }
}
/* The method `messageUppercase()` is called on every button click, mouse hover 
or other event that is defined on the page with the `v-on directive`. So every
time the page re-renders.*/
  1. คุณสมบัติที่คำนวณได้จะถูกเรียกเมื่อมีการเปลี่ยนแปลงค่าคุณสมบัติที่ถูกอ้างอิงโดยthisคำในคำจำกัดความของฟังก์ชัน
<p>Uppercase message: {{ messageUppercase }}</p> 
data() {
 return {
    message: "I love Vue.js"
   }
 },
computed: {
 messageUppercase() {
    console.log("messageUpercase");
    return this.message.toUpperCase();
 }
}
/* The computed property messageUppercase is only called when the propery message is
changed. Not on other events (clicks, mouse hovers,..) unless of course a specific 
event changes the value of message.  */

ใช้เวลาออกไปที่นี่คือการปฏิบัติที่ดีที่สุดที่จะใช้คุณสมบัติในกรณีที่วิธีการที่ไม่ได้ถูกเรียกว่ามีcomputedv-on directive

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