“我正在参加「掘金·启航计划」”
对于各个框架的语法糖。
我如果只是看文档,结果大概率会是,我知道这个东西,只是知道而已。这个语法糖在什么时候使用?我用这个方法不也是一样可以做出来吗?
这些疑问如果没有真实场景和业务的打磨,对框架的就只是停留在会用的阶段。高质量的代码就拜拜。
下面将根据自己实际业务,探讨语法糖的使用场景、分析利弊。
个人总结梳理。如有错误,欢迎指正!
语法糖 @const
场景示例:做一个二层菜单的功能(当前看起来是手风琴效果...,后续有新想法会继续使用这个例子),步骤如下。
- 模拟出菜单格式(此处只是模拟数据用来使用
@const语法糖,具体业务具体分析。) - 在
html中循环 - 写入用到的样式
<script lang='ts'>
const menuList = [
{ title: '首页' },
{ title: '系统管理', children: [ { title: '菜单管理' }, { title: '项目管理' } ] },
{ title: '文档管理', children: [ { title: '个人文档' } ] },
]
</script>
{#each menuList as menu}
<p>
{menu.title} {#if menu.children && menu.children.length > 0}<i> > </i>{/if}
</p>
{#if menu.children && menu.children.length > 0}
{#each menu.children as menuChild}
<div class='submenu'>
{menuChild.title}
</div>
{/each}
{/if}
{/each}
<style>
p {color: #000;}
.submenu {display: none;color: #000000;}
</style>
我们可以发现,用到了两次:menu.children && menu.children.length > 0
方案一:使用函数 isHasChildHandle
<script lang='ts'>
const isHasChildHandle = (menu) => menu && menu.length > 0
</script>
{#each menuList as menu}
<div>
{menu.title} {#if isHasChildHandle(menu)}<i> > </i>{/if}
</div>
{#if isHasChildHandle(menu)}
...
{/if}
{/each}
可以看出重复代码减少了,如果需要修改也会方便很多,但isHasChildHandle还是会运行两次。
大多数时候我们会觉得无所谓,只是改了两个地方,但是如果是完成下面的功能(未使用我们的方法,因为那并不是解决方案):
<script lang='ts'>
let active = '首页'
const menuList = [
{ title: '首页', children: [] },
{ title: '系统管理', children: [ { title: '菜单管理' }, { title: '项目管理' } ] },
{ title: '文档管理', children: [ { title: '个人文档' } ] },
]
const menuClick = (menu) => {
active = menu.title
}
</script>
{#each menuList as menu}
<div
class="menu"
class:has-child={menu.children && menu.children.length > 0}
class:active={menu.title === active}
on:click={() => menuClick(menu)}
>
{menu.title} {#if menu.children && menu.children.length > 0}<i> > </i>{/if}
</div>
{#if menu.children && menu.children.length > 0}
{#each menu.children as menuChild}
<div
class='submenu'
class:active={menu.title === active}
class:block={active === menu.title}
>
{menuChild.title}
</div>
{/each}
{/if}
{/each}
<style>
.menu {padding: 10px;cursor: pointer;font-size: 16px;}
.menu:hover {color: #7c88a0;}
.submenu {display: none;color: #000000;}
.block {display: block}
.active {color: #0b69a8;}
</style>
这段代码中我们会根据计算结果来动态的更新:class if,甚至在submenu中的one-child判断条件还不相同。
我尝试来分解一下代码,看看在一次循环中需要运算的语句:
class:has-child={menu.children && menu.children.length > 0}class:active={menu.title === active}{#if menu.children && menu.children.length > 0}<i> > </i>{/if}{#if menu.children && menu.children.length > 0}class:active={menu.title === active}class:block={active === menu.title}
严谨的来说:在一次循环中需要运算7*menuList.length次,使用isHasChildHandle仅仅是使代码量减少了,实际运算次数并没有减少。
想象一下,如果放在复杂业务中需要计算的次数非常多怎么办?是否意味着代码跑的慢?
这里是补充:若在
submenu中再增加一行class:one-child={menu.children && menu.children.length === 1},子循环中增加条件后,再想想复杂度!((3*menu.children.length)*menuList.length)
方案二:使用 @const
先看一下官方文档的解释:文档链接
标签{@const ...}定义了一个局部常量。
仅允许作为
{#if}、{:else if}、{:else}、{#each}、{:then}、{:catch}、<Component />、<svelte:fragment />的直接子集(as direct child)。
与原生JavaScript一样@const:它是只读的、不能分配的、它的作用域仅限于声明它的块级。
不要问有没有
let,只能说暂时没有,且@const还有一些小问题存在。建议关注github.
修改后的代码如下:
{#each menuList as menu}
{@const hasChild = menu.children && menu.children.length > 0}
{@const isActive = active === menu.title}
<div
class="menu"
class:has-child={hasChild}
class:active={isActive}
on:click={() => menuClick(menu)}
>
{menu.title} {#if hasChild}<i> > </i>{/if}
</div>
{#if hasChild}
{#each menu.children as menuChild}
<div
class='submenu'
class:active={isActive}
class:block={isActive}
>
{menuChild.title}
</div>
{/each}
{/if}
{/each}
// {isActive} // ReferenceError: isActive is not defined
再次查看在一次循环中需要运算的语句:
{@const hasChild = menu.children && menu.children.length > 0}{@const isActive = active === menu.title}
严谨的来说需要:在一次循环中需要运算3 * menu.length次,比较能够看出对性能的提升。
如果你想在线查看最终结果:在线预览