js 中の関数オブジェクト#
funcName()
と funcName
を区別することに注意してください。
関数を定義する場合、
function addOne(num){
return num++
}
addOne(1)
は、その関数を実行することを意味します。
一方、addOne
は関数オブジェクト自体を表します。例を挙げると、
let tempFunc = addOne // tempFunc も関数で、addOne と同じです
let tempResult = addOne(5) // tempResult は 6 です
引数のない関数の場合、これらの場合を区別するのはより困難です。
function printHello(){
console.log("Hello")
}
// ---------
printHello() // 1 回関数を実行し、Hello を出力します
let great = printHello // great は printHello と同じです
great() // 1 と同じです
この違いは、Web イベント処理において非常に重要です。例を挙げると(Vue)
<script setup>
function handleMyEvent(){
console.log("hello")
}
</script>
<template>
<!-- ここではカスタムコンポーネントがあり、内部で myEvent イベントを発行しています -->
<myComponent @myEvent="handleMyEvent"></myComponent>
<myComponent @myEvent="handleMyEvent()"></myComponent>
<myComponent @myEvent="console.log('hello')"
</template>
上記のコードでは、最初のコンポーネントはイベントにコールバック関数をバインドし、2 番目のコンポーネントはイベントが発生した後に関数本体(hello を出力)を実行します。これは 3 番目のコンポーネントと同等です。
また、コンポーネント内で発生するイベントには引数を指定することもできます。イベントに引数を指定する場合、最初の方法のみが正しく引数を受け取ることができます。この場合、handleMyEvent(id)
関数定義時に引数を受け取る必要があります。
以下はいくつかの方法の違いの解説です。
<script setup>
const id = ref(1)
const name = ref("David")
function handleEvent(id, name){
console.log(id + ' ' + name)
}
</script>
<template>
<!-- 子コンポーネントで defineEmits(['myEvent', id, name]) としています -->
<myComponent @myEvent="handleEvnet"></myComponent> <!--✅-->
<myComponent @myEvent="handleEvnet(id,name)"></myComponent> <!-- ❌ -->
<myComponent :id="id" :name="name" @myEvent="handleEvent(id,name)"></myComponen>
<myComponent :id="id" :name="name" @myEvent="handleEvent"></myComponen>
</template>
3 番目の方法は正常に動作しますが、イベントが発生すると、引数はコンポーネント内から直接渡されるのではなく、このレベルのコンポーネントのid
とname
が直接引数として関数本体に渡されます。
4 番目の方法は、子コンポーネント内部から渡された引数を受け取ります。
結論#
親子コンポーネント間でデータを渡す場合、冗長なデータの受け渡しを行わないように注意してください。4 番目の方法は正常に動作しますが、もし情報がサブコンポーネント内にある場合、3 番目の方法の方が優れています。
Vue のリスナー#
⚠️ コンポーネントのプロパティを監視する場合、getter を渡す必要があります。props.name
のように直接使用することはできません。
<script setup>
const props = defineProps(['id','name'])
watch(()=>props.id, function(newValue, oldValue){
// ...
})
</script>