Subscribe on changes!

Templates do not use toString() on objects

avatar
Jun 11th 2021

Version

3.1.1

Reproduction link

https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8aDE+e3sgbXNnIH19PC9oMT5cbiAgPGgxPnt7IG90aGVyTXNnIH19PC9oMT5cbiAgPGgxPnt7IG1zZy50b1N0cmluZygpIH19PC9oMT5cbiAgPGgxPnt7IG90aGVyTXNnLnRvU3RyaW5nKCkgfX08L2gxPlxuPC90ZW1wbGF0ZT5cblxuPHNjcmlwdCBzZXR1cD5cbmNvbnN0IG1zZyA9IHtcbiAgZm9vOiBcImJhclwiXG59XG5tc2cudG9TdHJpbmcgPSAoKSA9PiBcIkhlbGxvXCJcbiAgXG5jbGFzcyBUZXN0IHtcbiAgY29uc3RydWN0b3IgKCkge1xuICAgIHRoaXMuYmF6ID0gXCJidXpcIlxuICB9XG4gIHRvU3RyaW5nICgpIHtcbiAgICByZXR1cm4gXCJXb3JsZFwiXG4gIH1cbn1cbiAgXG5jb25zdCBvdGhlck1zZyA9IG5ldyBUZXN0KClcbjwvc2NyaXB0PiJ9

Steps to reproduce

  1. Render an object in a template that has a non-default toString() method

What is expected?

In Vue 2, the template would render with the result of calling toString() on the object.

It would check if the object's toString property was different from Object.toString.

https://github.com/vuejs/vue/blob/dev/src/shared/util.js#L81

What is actually happening?

In Vue 3.1.1, the template renders with the result of running JSON.stringify on the object.

It only checks that it's working with an object.

https://github.com/vuejs/vue-next/blob/master/packages/shared/src/toDisplayString.ts


This feels like a breaking change, but I don't see it listed anywhere. Confusingly, however, I've also seen zero people talking about this being a problem!

Obviously, I can just call .toString() everywhere that I was relying on this behavior, but that's a bit tedious.

avatar
Jun 11th 2021

Confusingly, however, I've also seen zero people talking about this being a problem!

I personally only every "dumped" objects in interpolations for debugging. I've never seen toString() being used in that way anywhere. I know it exists, but you are kind of the first person I learn of that relies on this behavior.

That may be just me, of course, but to me it seems this is kind of a niche thing to do, which might explain why it's not being talked about.

That being said, I would think it makes sense to implement the Vue 2 behavior in the sense of a fix. I personally don't think this was an intentional breaking change with a big reason behind it.

avatar
Jun 11th 2021

Yeah, I had a feeling it wasn't very common practice.

I (ab)used the behavior almost exclusively with a language system I'd developed for a game. The vast majority of the usage is in string interpolation, so it's not like too many things broke. It just made for quite a mess when I first got the project to compile, haha :p

avatar
Jun 14th 2021

As a workaround, you can use a regular function.

The relevant commit in Vue 2 was https://github.com/vuejs/vue/commit/0e4e45ec741416e0042c29a53bbc0e58c8663f6e

avatar
Jul 29th 2021

The fix from Vue 2 was retained in Vue 3 at first, and was also proposed to be retained in #1100, but was (accidentally?) removed in 3c60d40827f65cbff024cfda4bb981a742bb83a7. I've submitted a pull request to put the old behavior back