'Vue JS: reactive syntax

While I was trying to grasp reactivity fundamentals and its syntax I've encountered following problem. Consider this snippet:

const app = Vue.createApp({
   data: dataFunction,
   methods: {method1:  methodImpl}
})
var dataObj = {
    title: 'Holiday',
    author: 'Stanley Middleton',
    age: 45
}
function dataFunction (){
    return dataObj
}
var methodsObj = {
    method1:  methodImpl
    
}
function methodImpl (){
    this.title = 'Infinite Jest'
}
app.mount('#app')

and html behind it:

<div id="app">
        [...]
        <div @click="method1">change book title</div>
</div>

This code works and I was able to extract data into separate function and object but how can I do it with method ? This methods: methodsObj doesn't work - obviously. I want to be able to use my methodsObj in createApp initialization. Is it possible? I know it is purely academic but such exercises help me understand syntax and object relations.



Solution 1:[1]

In JavaScript, vars are hoisted, but their initializations are not. functions and their definitions are also hoisted. Your code relies on hoisting, which can be problematic.

Here's a visualization of the hoisting in your original working code:

// ? HOISTED DECLARATIONS
var dataObj = undefined;
function dataFunction (){
    return dataObj
}
var methodsObj = undefined;
function methodImpl (){
    this.title = 'Infinite Jest'
}
// ? HOISTED DECLARATIONS

const app = Vue.createApp({
   data: dataFunction,
   methods: {method1:  methodImpl} // ? methodImpl declared above
})
// INITIALIZATION
dataObj = {
    title: 'Holiday',
    author: 'Stanley Middleton',
    age: 45
}
// INITIALIZATION
methodsObj = {
    method1:  methodImpl
}

app.mount('#app')

Now consider that same code, but replace methods: {method1: methodImpl} with methods: methodsObj:

// ? HOISTED DECLARATIONS
var dataObj = undefined;
function dataFunction (){
    return dataObj
}
var methodsObj = undefined;
function methodImpl (){
    this.title = 'Infinite Jest'
}
// ? HOISTED DECLARATIONS

const app = Vue.createApp({
   data: dataFunction,
   methods: methodsObj // ? methodsObj undefined above, so method1 would be undefined in the app
})
// INITIALIZATION
dataObj = {
    title: 'Holiday',
    author: 'Stanley Middleton',
    age: 45
}
// INITIALIZATION
methodsObj = {
    method1:  methodImpl
}

app.mount('#app')

The issue with methodsObj in the example above can be fixed by declaring and initializing it before usage (which is generally a best practice):

// declare and initialize vars here...
var dataObj = {
    title: 'Holiday',
    author: 'Stanley Middleton',
    age: 45
}
function dataFunction (){
    return dataObj
}
var methodsObj = {
    method1:  methodImpl
    
}
function methodImpl (){
    this.title = 'Infinite Jest'
}

// now, use the declarations from above
const app = Vue.createApp({
   data: dataFunction,
   methods: methodsObj
})

app.mount('#app')

And here's the visualization of the hoisting above:

// ? HOISTED DECLARATIONS
var dataObj = undefined;
function dataFunction (){
    return dataObj
}
var methodsObj = undefined;
function methodImpl (){
    this.title = 'Infinite Jest'
}
// ? HOISTED DECLARATIONS

// INITIALIZATION
dataObj = {
    title: 'Holiday',
    author: 'Stanley Middleton',
    age: 45
}
// INITIALIZATION
methodsObj = {
    method1:  methodImpl
}

const app = Vue.createApp({
   data: dataFunction,
   methods: methodsObj // ? methodsObj declared and initialized above
})

app.mount('#app')

demo

One of the motivations of const and let (introduced in ES2015) was to avoid common bugs from var hoisting, such as you observed above. If you had used const/let instead of var in your original code, the compiler would've thrown an error, which might've signaled to you then that the declaration should be moved above the usage. Consider using a linter that discourages the use of var.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1