第二个脚本读不到第一个脚本中声明的var变量,因为变量提升仅限于单个块内的创建阶段,块间不共享执行上下文;let/const存在tdz,动态插入脚本开启新上下文,修改script.innerhtml不触发重执行。

为什么第二个<script>里读不到第一个里声明的var变量</script>
因为变量提升只发生在“创建阶段”,而赋值在“执行阶段”——这两个阶段被脚本块严格切割。浏览器按 HTML 顺序逐个加载 <script></script>,每个块内完成自己的提升和执行,但块之间不共享执行时机。
常见错误现象:ReferenceError: a is not defined 或更隐蔽的 a 是 undefined,尤其当第二个脚本试图读取第一个脚本中 var a = 1 的值却失败时。
- 如果
<script>var a = 1;</script>在前,<script>console.log(a);</script>在后 → 输出1 - 若顺序颠倒 → 第二个脚本执行时,第一个脚本还没加载,
a确实未声明,报ReferenceError - 如果第一个脚本用
let a = 1,哪怕位置在前,第二个脚本仍会报错——let不提升,且存在暂时性死区(TDZ)
function声明能跨<script>调用,但别以为就安全了</script>
function 声明会被完整提升到全局上下文的创建阶段,挂载到 window 上,所以只要它所在的 <script></script> 已加载完毕(哪怕还没执行到函数体),后续脚本就能调用它。
但这不等于“安全”——执行时机仍可能出问题。
- 前一个
<script></script>中写function init() { console.log('ready'); }→ 后一个可直接init() - 但如果前一个脚本里是
const init = () => {}或var init = function() {},则只提升变量名(init为undefined),调用会报TypeError - 即便函数已提升,若其内部依赖 DOM 元素,而调用发生在
解析前,仍会操作不到节点
动态插入的<script>不会延续原有执行流</script>
用 document.createElement('script') 插入的脚本,会触发一次新的、独立的全局执行上下文创建流程——它有自己的变量提升阶段,不继承之前脚本中 let/const 的值,也不感知前序脚本中尚未执行的赋值语句。
容易踩的坑:以为“插进去就等于接在上一个 <script></script> 后面”,结果发现变量突然变 undefined,或函数调用报错。
- 默认行为是
async = true,下载完立刻执行,不保证顺序;需显式设script.async = false才能同步阻塞(慎用) -
script.defer = true仅对同域有效,且只延迟到 DOM 解析完成,不解决跨脚本变量链断裂问题 - 更可靠的做法是封装成 Promise:
loadScript('a.js')
直接改<script>标签的innerHTML根本不会更新变量</script>
修改 <script id="datas"></script> 的 innerHTML 只改变 DOM 文本,不会触发 JavaScript 重新解析与执行,因此变量值不会更新。
例如:document.getElementById("datas").innerHTML = `data = { key:"BCSD123" };` —— 这行代码执行后,data.key 仍是原始值。
- ✅ 正确做法:把
data当作已声明的全局对象,直接修改属性,如data.key = "BCSD123" - ⚠️ 确保变量作用域正确:必须是
var data = {...}或裸赋值data = {...},不能是let/const声明 - ❌ 避免
eval()等危险方案:虽可通过eval(scriptElement.textContent)强制执行,但有严重 XSS 风险与性能问题
let/const 声明的变量哪怕物理位置靠前,也无法被后续脚本访问;动态插入的脚本永远是新上下文,跟前面的变量毫无关系。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











