Files
test-repo/docs/.vitepress/theme/components/appendix/computer-fundamentals/StaticVsDynamicDemo.vue
T
sanbuphy f44c842fe7 feat(docs): update computer fundamentals content and demos
- Refactor frontend framework demo descriptions for clarity
- Remove interactive features from triad and field map demos
- Add new computer organization and DSL documentation links
- Split type systems and compilers into separate pages
- Enhance power-on-to-web article with relay race analogy
- Add new interactive demos for type systems and compilation
- Improve visual presentation of boot process and hardware flow
- Introduce new Vibe Coding flow demo component
2026-02-25 01:38:27 +08:00

132 lines
4.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="static-vs-dynamic-demo">
<h4>🔍 静态类型 vs 动态类型实时对比</h4>
<p class="desc">选择一段代码观察两种类型系统的不同行为</p>
<div class="example-selector">
<button
v-for="(ex, i) in examples"
:key="i"
:class="['ex-btn', { active: selected === i }]"
@click="selected = i"
>
{{ ex.label }}
</button>
</div>
<div class="comparison">
<div class="panel static-panel">
<div class="panel-header">
<span class="badge">静态类型TypeScript</span>
<span class="timing"> 编译时检查</span>
</div>
<pre class="code-block">{{ examples[selected].staticCode }}</pre>
<div :class="['result', examples[selected].staticOk ? 'ok' : 'err']">
{{ examples[selected].staticResult }}
</div>
</div>
<div class="vs">VS</div>
<div class="panel dynamic-panel">
<div class="panel-header">
<span class="badge dynamic">动态类型JavaScript</span>
<span class="timing"> 运行时检查</span>
</div>
<pre class="code-block">{{ examples[selected].dynamicCode }}</pre>
<div :class="['result', examples[selected].dynamicOk ? 'ok' : 'err']">
{{ examples[selected].dynamicResult }}
</div>
</div>
</div>
<div class="insight">
💡 {{ examples[selected].insight }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const selected = ref(0)
const examples = [
{
label: '变量赋值',
staticCode: `let name: string = "Alice"
name = 42 // ❌ 编译错误`,
dynamicCode: `let name = "Alice"
name = 42 // ✅ 没问题`,
staticResult: '❌ Type "number" is not assignable to type "string"',
dynamicResult: '✅ 运行正常,name 变成了 42',
staticOk: false,
dynamicOk: true,
insight: '静态类型在你写代码时就发现错误,动态类型要等到运行时才知道。'
},
{
label: '函数参数',
staticCode: `function add(a: number, b: number) {
return a + b
}
add("1", 2) // ❌ 编译错误`,
dynamicCode: `function add(a, b) {
return a + b
}
add("1", 2) // ✅ 返回 "12"`,
staticResult: '❌ Argument of type "string" is not assignable to parameter of type "number"',
dynamicResult: '✅ 返回 "12"(字符串拼接,不是数学加法!)',
staticOk: false,
dynamicOk: true,
insight: '动态类型的"灵活"有时是 bug 的温床——你期望 3,却得到 "12"。'
},
{
label: '属性访问',
staticCode: `interface User { name: string }
let user: User = { name: "Bob" }
console.log(user.age) // ❌ 编译错误`,
dynamicCode: `let user = { name: "Bob" }
console.log(user.age) // ✅ 输出 undefined`,
staticResult: '❌ Property "age" does not exist on type "User"',
dynamicResult: '✅ 输出 undefined(不报错,但可能导致后续逻辑出错)',
staticOk: false,
dynamicOk: true,
insight: '静态类型能在编译时捕获拼写错误和属性缺失,动态类型只会默默返回 undefined。'
}
]
</script>
<style scoped>
.static-vs-dynamic-demo {
padding: 20px;
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
margin: 16px 0;
background: var(--vp-c-bg-soft);
}
h4 { margin: 0 0 4px; }
.desc { color: var(--vp-c-text-2); font-size: 14px; margin: 0 0 16px; }
.example-selector { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.ex-btn {
padding: 6px 14px; border-radius: 6px; border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg); cursor: pointer; font-size: 13px; transition: all 0.2s;
}
.ex-btn.active { background: var(--vp-c-brand-1); color: #fff; border-color: var(--vp-c-brand-1); }
.comparison { display: flex; gap: 12px; align-items: stretch; }
.panel { flex: 1; border-radius: 8px; border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); overflow: hidden; }
.panel-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; background: var(--vp-c-bg-soft); border-bottom: 1px solid var(--vp-c-divider); }
.badge { font-size: 12px; font-weight: 600; color: var(--vp-c-brand-1); }
.badge.dynamic { color: #e5a00d; }
.timing { font-size: 11px; color: var(--vp-c-text-3); }
.code-block { padding: 12px; margin: 0; font-size: 12px; line-height: 1.6; white-space: pre-wrap; overflow-x: auto; }
.result { padding: 8px 12px; font-size: 12px; border-top: 1px solid var(--vp-c-divider); }
.result.ok { background: #f0fdf4; color: #166534; }
.result.err { background: #fef2f2; color: #991b1b; }
.vs { display: flex; align-items: center; font-weight: 700; color: var(--vp-c-text-3); font-size: 14px; }
.insight { margin-top: 12px; padding: 10px 14px; background: var(--vp-c-brand-soft); border-radius: 8px; font-size: 13px; }
@media (max-width: 640px) {
.comparison { flex-direction: column; }
.vs { justify-content: center; padding: 4px 0; }
}
</style>