matejcik
matejcik

Reputation: 2072

Vue.js object proxies: props not showing in Object.keys

Vue.js proxies its objects to catch property accesses. I seem to have found a leak in the abstraction: Object.keys doesn't return props in the list of keys.

With the following Vue component:

function callMe() {
  var comp = Vue.component("comp", {
    template: "<button @click='clickMe()'>xxx</button>",
    props: {
        label: String,
        cardId: String,
        collapsible: {
            type: Boolean,
            default: true,
        },
        collapsed: Boolean,
    },
    data() {
        console.log(Object.keys(this))
        console.log(this.collapsible)
        console.log(Object.keys(this).includes("collapsible"))
        return { isCollapsed: this.collapsed }
    },
    methods: {
       clickMe(){
         console.log(this)
       } 
    }

  })
  var vm = new Vue({
    el: '#root',
    template: "<comp></comp>",
  })
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id='root'>
 
 <button @click="clickMe()" >Click Me</button>

</div>

The console output is:

(29) ["_uid", "_isVue", "$options", "_renderProxy", "_self", "$parent", "$root", "$children", "$refs", "_watcher", "_inactive", "_directInactive", "_isMounted", "_isDestroyed", "_isBeingDestroyed", "_events", "_hasHookEvent", "_vnode", "_staticTrees", "$vnode", "$slots", "$scopedSlots", "_c", "$createElement", "$attrs", "$listeners", "_watchers", "_props", "toggleThis"]
true
false

(Interestingly, when I call the check later, the isCollapsed item is in the list. You'll also notice that clickMe method is also present. It seems that only props are left out.)

Why is this happening?

More generally, how does Vue's Proxy object emit a different set of keys than it can then access?

This is a problem for me because I'm trying something fancy with pug-vdom and that internally uses Object.keys to enumerate the variables to inject into the Pug template.

Is this a Vue bug? Alternately, is it possible to access a list of props keys from the this object, and export an object whose keys contain the props as well?

edit: added a runnable code snippet that demonstrates the problem.

Upvotes: 0

Views: 3295

Answers (1)

Helping hand
Helping hand

Reputation: 2920

Object.keys() does not iterate over prototype properties.
Also child component is inherited from root component. This means props & data fields must be inside __proto__ of child components.

Hence if we do Object.keys(this__proto__).includes("collapsible") , it returns true in child component.

If you want to access those fields from child components then use this.$props and this.$data .

function callMe() {
  var comp = Vue.component("comp", {
    template: "<button @click='clickMe()'>xxx</button>",
    props: {
        label: String,
        cardId: String,
        collapsible: {
            type: Boolean,
            default: true,
        },
        collapsed: Boolean,
    },
    data() {
        console.log('Inside Child:',Object.keys(this))
        console.log(this.collapsible)
        console.log(Object.keys(this.__proto__).includes("collapsible"))
        console.log(Object.keys(this).includes("collapsible"))
        return { isCollapsed: this.collapsed }
    },
    methods: {
       clickMe(){
         console.log(this)
       } 
    }

  })
  var vm = new Vue({
    el: '#root',
    template: "<comp></comp>",
    props:{
    jack:{
          type: Boolean,
          default: true
         }
    },
    data(){
      console.log('Inside parent:', this.jack)
      return {}
    }
  })
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id='root'>
 
 <button @click="clickMe()" >Click Me</button>

</div>

Upvotes: 1

Related Questions