函数定义

 


### 6.5.1 问题:为什么是 `() => ({})` 而不是 `() => {}`? **疑问代码**: ```typescript state: () => ({ // ← 为什么多了一层括号? isLogin: false }) // 为什么不是这样? state: () => { // ← 这种写法是错误的 isLogin: false } ``` --- ### 6.5.2 答案:这是箭头函数返回对象的语法 **核心语法**:箭头函数返回对象时,必须用圆括号包裹对象 ```typescript // ✅ 正确:用圆括号包裹对象 const fn1 = () => ({ name: 'Alice' }); // ❌ 错误:没有圆括号,会被识别为代码块 const fn2 = () => { name: 'Alice' }; // ✅ 正确:显式 return const fn3 = () => { return { name: 'Alice' }; }; ``` --- ### 6.5.3 语法解析 #### 语法 1:`() => ({})` 箭头函数直接返回对象 ```typescript state: () => ({ isLogin: false }) ``` **解析**: ``` state: () => ({ isLogin: false }) │ │ └─────────────────┘ │ │ │ │ │ 返回的对象字面量 │ │ │ └─ 箭头(=>) │ └─ 参数列表(空) ``` **等价写法**: ```typescript // 写法 1:箭头函数直接返回对象(简洁) state: () => ({ isLogin: false }) // 写法 2:箭头函数 + return(完整) state: () => { return { isLogin: false }; } // 写法 3:传统函数 state: function() { return { isLogin: false }; } ``` --- #### 语法 2:`() => {}` 箭头函数的代码块 ```typescript // ❌ 错误示例 state: () => { isLogin: false // ← 这会被解析为标签(label),不是对象! } ``` **为什么错误**: - 在 JavaScript 中,`{ }` 可以表示**代码块**或**对象字面量** - 箭头函数的 `=>` 后面紧跟 `{ }` 时,会被解析为**代码块**,而不是对象 - `{ isLogin: false }` 在代码块中会被解析为: - `isLogin:` 是一个**标签(label)** - `false` 是一个**表达式语句** **完整解释**: ```typescript // 这段代码: () => { isLogin: false } // 会被解析为: function() { isLogin: false // 标签(label),类似于 goto 的标签 // 等价于: // label: false; } ``` **标签(Label)示例**: ```typescript // JavaScript 的标签语法 outerLoop: for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { if (j === 3) break outerLoop; // 跳出外层循环 } } ``` --- ### 6.5.4 JavaScript 语法规则详解 #### 规则 1:`{ }` 的歧义性 ```typescript // 情况 1:对象字面量 const obj = { name: 'Alice' }; // ✅ 明确是对象 // 情况 2:代码块 { console.log('Hello'); // ✅ 明确是代码块 } // 情况 3:箭头函数后的歧义 const fn = () => { console.log('Hello'); // ✅ 这是代码块 }; const fn2 = () => ({ name: 'Alice' // ✅ 这里的括号强制解析为对象 }); ``` --- #### 规则 2:箭头函数的语法优先级 ```typescript // 语法 A:单行表达式(不需要 return 关键字) () => expression // 自动返回表达式的值 // 语法 B:代码块(需要 return 才能返回值) () => { // 代码块 return value; // 必须显式 return } // 关键:对象字面量属于表达式,但 { } 看起来像代码块 () => { name: 'Alice' } // ❌ 被解析为代码块 () => ({ name: 'Alice' }) // ✅ 用括号强制解析为表达式 ``` --- ### 6.5.5 完整对比示例 #### 示例 1:箭头函数的各种写法 ```typescript // ✅ 写法 1:直接返回对象(推荐) const fn1 = () => ({ name: 'Alice', age: 30 }); // ✅ 写法 2:使用 return const fn2 = () => { return { name: 'Alice', age: 30 }; }; // ✅ 写法 3:传统函数 function fn3() { return { name: 'Alice', age: 30 }; } // ❌ 写法 4:错误(没有圆括号) const fn4 = () => { name: 'Alice', age: 30 }; // 等价于: const fn4 = () => { name: 'Alice', // 标签 age: 30 // 表达式语句 }; // 返回 undefined(没有 return) ``` --- #### 示例 2:Pinia state 的正确写法 ```typescript // ✅ 正确:箭头函数直接返回对象 export const useUserStore = defineStore('user', { state: () => ({ isLogin: false, userInfo: null }) }); // ✅ 正确:箭头函数 + return export const useUserStore = defineStore('user', { state: () => { return { isLogin: false, userInfo: null }; } }); // ✅ 正确:传统函数 export const useUserStore = defineStore('user', { state: function() { return { isLogin: false, userInfo: null }; } }); // ❌ 错误:没有圆括号 export const useUserStore = defineStore('user', { state: () => { isLogin: false, // 标签 userInfo: null // 表达式语句 // 没有 return,返回 undefined } }); ``` --- ### 6.5.6 为什么需要这个语法? #### 原因 1:箭头函数的设计 **箭头函数的语法糖**: ```typescript // 设计目标:让简单的函数更简洁 // 传统写法 function add(a, b) { return a + b; } // 箭头函数(单行表达式) const add = (a, b) => a + b; // 箭头函数(多行代码块) const add = (a, b) => { const result = a + b; return result; }; ``` **问题**:如何区分"单行表达式"和"代码块"? ```typescript // 表达式 () => 42 // 返回数字 42 () => 'hello' // 返回字符串 'hello' // 代码块 () => { // 代码块开始 console.log('hello'); return 42; } // 对象字面量的歧义 () => { x: 1 } // 这是代码块还是对象? // JavaScript 规则:优先解析为代码块 () => ({ x: 1 }) // 用括号强制解析为表达式 ``` --- #### 原因 2:对象字面量的特殊性 ```typescript // 对象字面量在赋值时的语法 const obj = { x: 1 }; // ✅ 明确是对象 // 但在箭头函数后会有歧义 const fn = () => { x: 1 }; // ^^^^^^^^ // 这是代码块还是对象? // // JavaScript 解析器: // 1. 看到 `=> {`,认为 `{` 是代码块开始 // 2. 看到 `x:`,认为是标签(label) // 3. 看到 `1`,认为是表达式语句 // 4. 代码块结束,没有 return,返回 undefined // 解决方案:用括号包裹 const fn = () => ({ x: 1 }); // ^^^^^^^ // 括号内只能是表达式,所以解析为对象 ``` --- ### 6.5.7 语法速查表 | 写法 | 含义 | 返回值 | |------|------|--------| | `() => ({ x: 1 })` | 箭头函数返回对象 | `{ x: 1 }` ✅ | | `() => { x: 1 }` | 箭头函数的代码块 | `undefined` ❌ | | `() => { return { x: 1 }; }` | 箭头函数代码块 + return | `{ x: 1 }` ✅ | | `() => x` | 箭头函数返回变量值 | `x` 的值 | | `() => { x }` | 箭头函数代码块 | `undefined` ❌ | --- ### 6.5.8 实际应用示例 #### 示例 1:Pinia Store 的 state ```typescript export const useUserStore = defineStore('user', { // ✅ 箭头函数直接返回对象(最简洁) state: () => ({ isLogin: false, userInfo: null, permissions: [] }), // ✅ 等价写法(如果需要逻辑) state: () => { const initialState = { isLogin: false, userInfo: null, permissions: [] }; return initialState; }, }); ``` --- #### 示例 2:Vue 组件的 data ```typescript // Vue 3 Composition API import { ref } from 'vue'; const count = ref(0); // 简单值用 ref // Vue 3 Options API export default { data() { return { // ✅ 返回对象 count: 0, message: 'hello' }; } }; // ❌ 错误:直接返回对象字面量 export default { data: () => { count: 0, // 标签 message: 'hello' // 表达式语句 // 没有 return } }; ``` --- #### 示例 3:React 组件的 state ```typescript // React 函数组件 function Counter() { const [count, setCount] = useState(0); // Hook // ... } // React 类组件 class Counter extends React.Component { state = { // ✅ 类属性,直接赋值 count: 0 }; } // ❌ 不相关的语法(仅作对比) const fn = () => { count: 0 // 标签,不是对象 }; ``` --- ### 6.5.9 调试技巧 #### 如何检测错误的写法? ```typescript // ❌ 错误写法 const state = () => { isLogin: false }; // 测试 console.log(state()); // undefined(而不是 { isLogin: false }) // ✅ 正确写法 const state = () => ({ isLogin: false }); console.log(state()); // { isLogin: false } ``` --- #### TypeScript 的类型检查 ```typescript // TypeScript 能够检测到错误 const fn1 = () => ({ x: 1 }); // ✅ 类型: () => { x: number } const fn2 = () => { x: 1 }; // ❌ 可能报错:x 没有定义(作为变量) // 显式类型注解 const fn3: () => { x: number } = () => ({ x: 1 }); // ✅ const fn4: () => { x: number } = () => { x: 1 }; // ❌ 类型错误 ``` --- ### 6.5.10 关键要点总结 1. **`()` 表示参数列表** - `()` 表示空参数列表 - 如果有参数:`(arg1, arg2) => ({ ... })` 2. **`=>` 表示箭头函数** - 分隔参数列表和函数体 3. **`({})` 表示返回对象** - **外层括号**:强制解析为表达式 - **内层花括号**:对象字面量 - **合起来**:`({ x: 1 })` 是包裹在括号中的对象字面量 4. **如果没有外层括号** - `{ x: 1 }` 会被解析为代码块 - `x:` 会被解析为标签 - 函数返回 `undefined` 5. **记忆口诀** ``` 箭头函数返回对象,外层括号不能少 () => ({ object }) ✅ 正确 () => { object } ❌ 错误 ``` --- ### 6.5.11 完整语法图解 ``` state: () => ({ isLogin: false }) │ │ │ └────────────────┘ │ │ │ │ │ │ │ 对象字面量 │ │ │ { isLogin: false } │ │ │ │ │ └─ 圆括号(强制解析为表达式) │ │ │ └─ 箭头(=>) │ └─ 参数列表(空) ``` **等价展开**: ```typescript state: function() { return { isLogin: false }; } ``` --- ### 6.5.12 常见错误与解决方案 | 错误代码 | 问题 | 解决方案 | |---------|------|---------| | `() => { x: 1 }` | 被解析为代码块 | 改为 `() => ({ x: 1 })` | | `() => { return { x: 1 } }` | 多余的代码块 | 改为 `() => ({ x: 1 })` | | `() => { x: 1, y: 2 }` | 多个标签 | 改为 `() => ({ x: 1, y: 2 })` | --- ### 6.5.13 最佳实践建议 ```typescript // ✅ 推荐 1:简单对象直接返回 state: () => ({ isLogin: false, userInfo: null }) // ✅ 推荐 2:需要逻辑时使用完整写法 state: () => { const defaultState = { isLogin: false, userInfo: null }; if (process.env.NODE_ENV === 'development') { defaultState.debugMode = true; } return defaultState; } // ❌ 避免:不必要的代码块 state: () => { return { isLogin: false }; } ``` --- **总结**:`state: () => ({})` 是箭头函数返回对象的简洁语法,外层括号是必需的,用于告诉 JavaScript 这是一个对象字面量,而不是代码块。 ---

 


 


 


数组
```typescript numbers.reduce( (total, num) => total + num, 0 ) ``` `reduce` 在这里的作用是**将数组中的所有元素累加起来**。 ## 逐步解析: ### 1. **基本语法** `reduce` 方法接收两个参数: - **回调函数**:对每个元素执行的函数 - **初始值**:累加的起始值(这里是 `0`) ### 2. **回调函数的参数** ```typescript (total, num) => total + num ``` - total:累加器,保存当前的累加结果 - num:当前正在处理的数组元素 ### 3. **执行过程** 假设调用 `sum(1, 2, 3, 4)`: - numbers 数组 = `[1, 2, 3, 4]` - 初始值 total = `0` 执行步骤: 1. 第一次:`total = 0 + 1 = 1` 2. 第二次:`total = 1 + 2 = 3` 3. 第三次:`total = 3 + 3 = 6` 4. 第四次:`total = 6 + 4 = 10` 最终返回 `10` ## 实际应用示例: ```typescript // 各种调用方式 console.log(sum(1, 2, 3, 4)); // 输出: 10 console.log(sum(5, 10, 15)); // 输出: 30 console.log(sum()); // 输出: 0(空数组,只返回初始值) // 也可以用数组调用 const numbers = [1, 2, 3, 4]; console.log(sum(...numbers)); // 输出: 10(展开运算符) ``` ## 如果没有 reduce,等效的实现: ```typescript function sum(...numbers: number[]): number { let total = 0; for (let i = 0; i < numbers.length; i++) { total += numbers[i]; } return total; } ``` 或者用 `for...of` 循环: ```typescript function sum(...numbers: number[]): number { let total = 0; for (const num of numbers) { total += num; } return total; } ``` `reduce` 的优势在于代码更简洁、函数式,而且可以链式调用其他数组方法。

 

    

 


 


 


 


 


 


特殊语法
分析一下面代码中单个问号?与双问号??的语法含义 ``` catch (error: any) { // if (type === 'run' || type === 'refreRun') { console.log('SQL执行失败:', error); const msg = error?.data?.msg || '';} if (savedState) { this.model = savedState.model ?? 0; this.data = savedState.data ?? {}; this.screen = savedState.screen ?? {}; this.analyze = savedState.analyze ?? {}; } ``` ## 代码中 `?` 与 `??` 的语法含义分析 ### 1. 可选链操作符 (`?.`) **语法含义:** - 可选链操作符允许安全地访问深层嵌套的对象属性,而不必显式验证每个中间引用是否有效。 - 如果引用为 `null` 或 `undefined`,表达式会短路返回 `undefined`。 **代码示例:** ```typescript const msg = error?.data?.msg || ''; ``` **等价写法:** ```typescript // 传统写法 const msg = (error !== null && error !== undefined && error.data !== null && error.data !== undefined) ? error.data.msg : undefined; const finalMsg = msg || ''; // 或者更简洁的传统写法 const msg = error && error.data && error.data.msg || ''; ``` **执行逻辑:** 1. 检查 `error` 是否为 `null` 或 `undefined` 2. 如果是,返回 `undefined`,不再继续访问 `.data` 3. 如果不是,继续访问 `error.data` 4. 检查 `error.data` 是否为 `null` 或 `undefined` 5. 如果是,返回 `undefined` 6. 如果不是,返回 `error.data.msg` 的值 7. 最后通过 `|| ''` 将 `undefined` 或假值转换为空字符串 --- ### 2. 空值合并操作符 (`??`) **语法含义:** - 空值合并操作符是一个逻辑操作符,当左侧操作数为 `null` 或 `undefined` 时, - 返回右侧操作数; - 否则返回左侧操作数。 **代码示例:** ```typescript this.model = savedState.model ?? 0; this.data = savedState.data ?? {}; this.screen = savedState.screen ?? {}; this.analyze = savedState.analyze ?? {}; ``` **等价写法:** ```typescript // 传统写法1:使用三元运算符 this.model = savedState.model !== null && savedState.model !== undefined ? savedState.model : 0; // 传统写法2:使用逻辑或(注意:这种方式有陷阱) this.model = savedState.model || 0; // 当 model = 0 或 false 时会错误地使用默认值 ``` **执行逻辑:** - 如果 `savedState.model` 是 `null` 或 `undefined`,使用默认值 `0` - 如果 `savedState.model` 是其他任何值(包括 `0`、`false`、`''`、`NaN`),都使用该值本身 --- ### 3. 两者的关键区别 | 操作符 | 名称 | 触发默认值的条件 | 典型使用场景 | |--------|------|-----------------|--------------| | `??` | 空值合并 | 仅当值为 `null` 或 `undefined` | 需要保留 `0`、`false`、`''` 等有效值 | | `||` | 逻辑或 | 值为假值(`null`、`undefined`、`0`、`false`、`''`、`NaN`) | 需要过滤所有假值,用默认值替换 | | `?.` | 可选链 | 访问不存在属性时不报错 | 安全访问深层嵌套对象 | --- ### 4. 组合使用示例 ```typescript // 可选链 + 空值合并的组合使用 const value = obj?.nested?.property ?? 'default'; // 等价于: const value = obj !== null && obj !== undefined && obj.nested !== null && obj.nested !== undefined ? (obj.nested.property ?? 'default') : 'default'; ``` --- ### 5. 注意事项 1. **不能与 `&&` 或 `||` 混用而不加括号:** ```typescript // ❌ 错误 - 语法错误 const result = null || undefined ?? 'default'; // ✅ 正确 const result = (null || undefined) ?? 'default'; ``` 2. **`??` 会保留假值:** ```typescript const count = 0 ?? 100; // 结果为 0 const count = 0 || 100; // 结果为 100 ``` 3. **可选链支持函数调用:** ```typescript const result = obj?.method?.(); // 仅当 obj.method 存在且为函数时才调用 ```

 


 


 


 


参考