Vue3又出新语法 到底何时才能折腾完?

前言

大家应该知道如果用 Vue3Composition API 定义一个响应式变量通常有两种形式,一种是用ref,另一种是reactive

<script setup>
import { ref, reactive } from 'vue'

const isLoading = ref(true)

const user = reactive({
  name: '令狐冲',
  age: 22,
  gender: '男'
})
script>

一般来说定义一个基本数据类型会用ref,而引用类型则会采用reactive,那么问题来了,ref虽然定义了一个基本数据类型,但实际上它却是一个引用类型,取值和赋值时必须要带上.value属性:

<script setup>
import { ref } from 'vue'

const isLoading = ref(true)

if (isLoading.value) {
  isLoading.value = false
}
script>

这就有点不太符合直觉了,很有可能一不小心就被写成了这样:

<script setup>
import { ref } from 'vue'

let isLoading = ref(true)

if (isLoading) {
  isLoading = false
}
script>

这要是有TSESLint的加持还好,要是没有的话可就不好找错误了,也不会产生什么有用的报错信息,而且每次都要带上这个.value实在是不好看,而且写起来也麻烦呀!

reactive的弊端是不能解构,解构就会失去响应性:

<script setup>
import { reactive } from 'vue'

const user = reactive({
  name: '令狐冲',
  age: 22,
  gender: '男'
})

// 这种写法通常达不到预期的效果
let { age } = user
age = 18
script>

可能有人会说,不是有toRefs吗?用了toRefs,就又会回到那个.value的问题上了:

<script setup>
import { reactive, toRefs } from 'vue'

const user = reactive({
  name: '令狐冲',
  age: 22,
  gender: '男'
})

let { age } = toRefs(user)
age.value = 18
script>

其实我个人觉得还好啦,因为已经写习惯了,再加上一直用TS有提示和自动补全,所以感觉没什么问题。

但知乎上类似于《为什么 vue3 删不掉 ref() 这样冗余的函数,但 svelte 可以?》这种问题深深的刺痛了大佬的内心,大佬自己的强迫症也犯了,毕竟他当年创造Vue的最成功要素之一就是方便。而如今这种冗余的写法却与方便毫不搭边儿,所以尤大无论如何也必须要解决这个问题,不能让人背后嚼耳根子说Vue写起来还没Svelte方便是不是?于是乎大佬先后创建了三次不同的语法糖,它们分别是:

  • 《[译]尤雨溪: Ref语法糖提案》
  • 《Vue第二波ref语法提案来袭 这次会进入到标准吗?》
  • 本文 (第二波语法糖的修改版)

我们先来简单的看一下,这三次语法糖的写法:

第一波语法糖

第一波主要是模仿了Svelte的写法,我们先来看看Svelte的中文官网给出来的一段例子:

<script>
export let title;

// 这将在“title”的prop属性更改时更新“document.title”
$: document.title = title;

$: {
  console.log(`multiple statements can be combined`);
  console.log(`the current title is ${title}`);
}
script>

这个$:是一种叫做label的语法,这种语法并不是Svelte自创的语法,而是一种长期在被废弃的边缘上疯狂试探的合法语法,只不过这种语法原本并不是这么用的,人家是用在嵌套循环上的:

let num = 0

outermost:
for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        if (i == 5 && j == 5) {
            continue outermost
        } else {
            console.log(i, j, 88)
        }
        num++
    }
}

console.log(num) //95

看不懂没关系啊,也没必要去弄懂这种语法,因为它不够直观,用处也不是很大,所以几乎没什么人用它!我在编辑器写这段代码的时候 ESLint 都直报错:

Vue3又出新语法 到底何时才能折腾完?_第1张图片

翻译:Label语法源于GOTO语句,使用它将会令代码变得难以理解、难以维护。—ESLint

不过既然没什么人在用,同时它还是JS的合法语法,那用它来告诉编译器这里是声明了一个ref变量岂不是很完美?于是乎尤大也搞了个和Svelte类似的语法:

<script setup>
ref: isLoading = true

if (isLoading) {
  isLoading = false
}
script>

那么大家为何会如此反对呢?就是因为label语法压根儿就不是这么用的,人家原本是为了和breakcontinue配合使用的,虽然在别的地方用也不算是语法错误,但你这么做明显是修改了JS原本的语意!虽然尤大表示很不服啊:为什么Svelte用这玩意你们都没说啥,我一用这玩意你们就开喷?!

个人感觉是因为Svelte从一开始就说自己是一个编译器,没有沉重的历史包袱,而Vue却恰恰相反。而且Svelte本身也不是什么主流框架,属于给那帮爱折腾的人玩的。但Vue不一样,已经有多少人要靠着Vue吃饭呢,并不是所有人都那么爱折腾的。

于是在万般无奈之下,尤大只好放弃了这个提案,但这件事在尤大心里始终还是挥之不去、如鲠在喉,于是乎他吸取了第一波语法糖的教学,卷头重来又起草了一份新提案:

第二波语法糖

<script setup>
let loading = $ref(true)

if (loading) {
  loading = false
}
script>

可以看到我们并没有引入$ref这个变量,这个变量是从哪来的的呢?是只要在

你可能感兴趣的:(vue.js,typescript,javascript)