复习面试题 - 打印题 - 闭包/变量提升/作用域链
题目 1:经典闭包问题
js
import { useState } from 'react'
export default function ClosureDemo() {
const [result, setResult] = useState('')
function testVarProblem() {
setResult('测试中...')
const results = []
// 经典闭包问题:var 在循环中的问题
for (var i = 0; i < 3; i++) {
setTimeout(function () {
results.push(`var问题: ${i}`)
if (results.length === 3) {
setResult(
results.join('\n') +
'\n解释:var是函数作用域,循环结束时i=3,所以都输出3'
)
}
}, 100 * results.length)
}
}
function testClosureSolution() {
setResult('测试中...')
const results = []
// 解决方案1:使用闭包
for (var i = 0; i < 3; i++) {
;(function (j) {
setTimeout(function () {
results.push(`闭包解决: ${j}`)
if (results.length === 3) {
setResult(
results.join('\n') +
'\n解释:立即执行函数创建了新的作用域,j保存了当时的i值'
)
}
}, 100 * results.length)
})(i)
}
}
function testLetSolution() {
setResult('测试中...')
const results = []
// 解决方案2:使用 let
for (let i = 0; i < 3; i++) {
setTimeout(function () {
results.push(`let解决: ${i}`)
if (results.length === 3) {
setResult(
results.join('\n') + '\n解释:let是块级作用域,每次循环都创建新的i'
)
}
}, 100 * results.length)
}
}
return (
<div>
<div>
<button onClick={testVarProblem}>测试 var 问题</button>
<button onClick={testClosureSolution}>测试闭包解决方案</button>
<button onClick={testLetSolution}>测试 let 解决方案</button>
</div>
<pre>结果:{result}</pre>
<div style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>
经典闭包问题:for循环中的异步操作
</div>
</div>
)
}import { useState } from 'react'
export default function ClosureDemo() {
const [result, setResult] = useState('')
function testVarProblem() {
setResult('测试中...')
const results = []
// 经典闭包问题:var 在循环中的问题
for (var i = 0; i < 3; i++) {
setTimeout(function () {
results.push(`var问题: ${i}`)
if (results.length === 3) {
setResult(
results.join('\n') +
'\n解释:var是函数作用域,循环结束时i=3,所以都输出3'
)
}
}, 100 * results.length)
}
}
function testClosureSolution() {
setResult('测试中...')
const results = []
// 解决方案1:使用闭包
for (var i = 0; i < 3; i++) {
;(function (j) {
setTimeout(function () {
results.push(`闭包解决: ${j}`)
if (results.length === 3) {
setResult(
results.join('\n') +
'\n解释:立即执行函数创建了新的作用域,j保存了当时的i值'
)
}
}, 100 * results.length)
})(i)
}
}
function testLetSolution() {
setResult('测试中...')
const results = []
// 解决方案2:使用 let
for (let i = 0; i < 3; i++) {
setTimeout(function () {
results.push(`let解决: ${i}`)
if (results.length === 3) {
setResult(
results.join('\n') + '\n解释:let是块级作用域,每次循环都创建新的i'
)
}
}, 100 * results.length)
}
}
return (
<div>
<div>
<button onClick={testVarProblem}>测试 var 问题</button>
<button onClick={testClosureSolution}>测试闭包解决方案</button>
<button onClick={testLetSolution}>测试 let 解决方案</button>
</div>
<pre>结果:{result}</pre>
<div style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>
经典闭包问题:for循环中的异步操作
</div>
</div>
)
}题目 2:基础变量提升
js
import { useState } from 'react'
export default function BasicHoistingDemo() {
const [result, setResult] = useState('')
function testHoisting() {
const results = []
// 模拟变量提升的例子
function hoistingExample() {
try {
results.push(`1. console.log(a): ${typeof a}`) // undefined
var a = 1
results.push(`2. console.log(a): ${a}`) // 1
results.push(`3. console.log(b): ${typeof b}`) // undefined
var b = function () {
return 2
}
results.push(`4. console.log(b()): ${b()}`) // 2
results.push(`5. console.log(c()): ${c()}`) // 3
function c() {
return 3
}
} catch (error) {
results.push(`错误: ${error.message}`)
}
}
hoistingExample()
setResult(
results.join('\n') + '\n\n解释:var和function声明会被提升,但赋值不会'
)
}
return (
<div>
<button onClick={testHoisting}>测试基础变量提升</button>
<pre>结果:{result}</pre>
</div>
)
}import { useState } from 'react'
export default function BasicHoistingDemo() {
const [result, setResult] = useState('')
function testHoisting() {
const results = []
// 模拟变量提升的例子
function hoistingExample() {
try {
results.push(`1. console.log(a): ${typeof a}`) // undefined
var a = 1
results.push(`2. console.log(a): ${a}`) // 1
results.push(`3. console.log(b): ${typeof b}`) // undefined
var b = function () {
return 2
}
results.push(`4. console.log(b()): ${b()}`) // 2
results.push(`5. console.log(c()): ${c()}`) // 3
function c() {
return 3
}
} catch (error) {
results.push(`错误: ${error.message}`)
}
}
hoistingExample()
setResult(
results.join('\n') + '\n\n解释:var和function声明会被提升,但赋值不会'
)
}
return (
<div>
<button onClick={testHoisting}>测试基础变量提升</button>
<pre>结果:{result}</pre>
</div>
)
}题目 3:复杂提升情况
js
import { useState } from 'react'
export default function ComplexHoistingDemo() {
const [result, setResult] = useState('')
function testComplexHoisting() {
const results = []
function complexExample() {
try {
// 嵌套函数的复杂提升
results.push(`1. 调用outer(): ${outer()}`)
function outer() {
results.push(`2. outer中调用inner(): ${inner()}`) // 重点
var inner = function () {
return 'inner表达式'
}
function inner() {
return 'inner声明'
}
results.push(`3. 重新赋值后inner(): ${inner()}`)
return 'outer完成'
}
} catch (error) {
results.push(`错误: ${error.message}`)
}
}
complexExample()
setResult(
results.join('\n') +
'\n\n解释:函数声明提升优先级高于变量声明,但变量赋值会覆盖'
)
}
return (
<div>
<button onClick={testComplexHoisting}>测试复杂提升情况</button>
<pre>结果:{result}</pre>
</div>
)
}import { useState } from 'react'
export default function ComplexHoistingDemo() {
const [result, setResult] = useState('')
function testComplexHoisting() {
const results = []
function complexExample() {
try {
// 嵌套函数的复杂提升
results.push(`1. 调用outer(): ${outer()}`)
function outer() {
results.push(`2. outer中调用inner(): ${inner()}`) // 重点
var inner = function () {
return 'inner表达式'
}
function inner() {
return 'inner声明'
}
results.push(`3. 重新赋值后inner(): ${inner()}`)
return 'outer完成'
}
} catch (error) {
results.push(`错误: ${error.message}`)
}
}
complexExample()
setResult(
results.join('\n') +
'\n\n解释:函数声明提升优先级高于变量声明,但变量赋值会覆盖'
)
}
return (
<div>
<button onClick={testComplexHoisting}>测试复杂提升情况</button>
<pre>结果:{result}</pre>
</div>
)
}题目 4:基础作用域链
js
import { useState } from 'react'
export default function BasicScopeDemo() {
const [result, setResult] = useState('')
function testScope() {
const results = []
var x = 1
function outer() {
var x = 2
function inner() {
results.push(`inner中的x: ${x}`) // undefined
var x = 3
results.push(`赋值后inner中的x: ${x}`) // 3
}
inner()
results.push(`outer中的x: ${x}`) // 2
}
outer()
results.push(`全局中的x: ${x}`) // 1
setResult(
results.join('\n') +
'\n\n解释:每个函数都有自己的作用域,变量查找沿作用域链向上'
)
}
return (
<div>
<button onClick={testScope}>测试基础作用域链</button>
<pre>结果:{result}</pre>
</div>
)
}import { useState } from 'react'
export default function BasicScopeDemo() {
const [result, setResult] = useState('')
function testScope() {
const results = []
var x = 1
function outer() {
var x = 2
function inner() {
results.push(`inner中的x: ${x}`) // undefined
var x = 3
results.push(`赋值后inner中的x: ${x}`) // 3
}
inner()
results.push(`outer中的x: ${x}`) // 2
}
outer()
results.push(`全局中的x: ${x}`) // 1
setResult(
results.join('\n') +
'\n\n解释:每个函数都有自己的作用域,变量查找沿作用域链向上'
)
}
return (
<div>
<button onClick={testScope}>测试基础作用域链</button>
<pre>结果:{result}</pre>
</div>
)
}题目 5:块级作用域
js
import { useState } from 'react'
export default function BlockScopeDemo() {
const [result, setResult] = useState('')
function testBlockScope() {
const results = []
function blockScopeExample() {
var varVariable = '全局var'
let letVariable = '全局let'
results.push(`1. 块外 var: ${varVariable}`)
results.push(`2. 块外 let: ${letVariable}`)
if (true) {
var varVariable = '块内var' // 覆盖外层var
let letVariable = '块内let' // 块级作用域新变量
const constVariable = '块内const'
results.push(`3. 块内 var: ${varVariable}`)
results.push(`4. 块内 let: ${letVariable}`)
results.push(`5. 块内 const: ${constVariable}`)
}
results.push(`6. 块外 var: ${varVariable}`) // 被覆盖了(重点)
results.push(`7. 块外 let: ${letVariable}`) // 还是原来的值
try {
results.push(`8. 块外访问const: ${constVariable}`)
} catch (e) {
results.push(`8. 块外访问const错误: ${e.name}`)
}
}
blockScopeExample()
setResult(
results.join('\n') + '\n\n解释:var是函数作用域,let/const是块级作用域'
)
}
return (
<div>
<button onClick={testBlockScope}>测试块级作用域</button>
<pre>结果:{result}</pre>
</div>
)
}import { useState } from 'react'
export default function BlockScopeDemo() {
const [result, setResult] = useState('')
function testBlockScope() {
const results = []
function blockScopeExample() {
var varVariable = '全局var'
let letVariable = '全局let'
results.push(`1. 块外 var: ${varVariable}`)
results.push(`2. 块外 let: ${letVariable}`)
if (true) {
var varVariable = '块内var' // 覆盖外层var
let letVariable = '块内let' // 块级作用域新变量
const constVariable = '块内const'
results.push(`3. 块内 var: ${varVariable}`)
results.push(`4. 块内 let: ${letVariable}`)
results.push(`5. 块内 const: ${constVariable}`)
}
results.push(`6. 块外 var: ${varVariable}`) // 被覆盖了(重点)
results.push(`7. 块外 let: ${letVariable}`) // 还是原来的值
try {
results.push(`8. 块外访问const: ${constVariable}`)
} catch (e) {
results.push(`8. 块外访问const错误: ${e.name}`)
}
}
blockScopeExample()
setResult(
results.join('\n') + '\n\n解释:var是函数作用域,let/const是块级作用域'
)
}
return (
<div>
<button onClick={testBlockScope}>测试块级作用域</button>
<pre>结果:{result}</pre>
</div>
)
}总结
- 闭包问题:var 是函数作用域,在循环中会共享变量,导致异步回调中访问的都是循环结束时的值;let/const 是块级作用域,每次循环都会创建新的作用域,不会共享变量
- 变量提升:var 和 function 声明会提升,但赋值不会;函数声明的提升优先级高于 var 声明,但后续的变量赋值会覆盖函数
- 作用域链:每个函数都有自己的作用域,变量查找沿作用域链向上