原始类型操作不产生函数或eval上下文,其行为由变量环境、作用域链和this共同决定;值以拷贝方式存储,参与运算或方法调用时触发隐式转换或临时包装。

JS 原始类型操作本身不产生函数或 eval 上下文,但它们的值在不同上下文中被读取、比较或传递时,会触发隐式行为——这些行为由执行上下文中的变量环境、作用域链和 this 共同决定。理解原始类型如何在上下文中“被对待”,比记住类型本身更重要。
原始值在变量环境中如何被存储
原始类型(string、number、boolean、null、undefined、symbol、bigint)在变量环境中以**值拷贝**方式存在,不共享引用。但在创建阶段,JS 引擎仍会为其预留空间,并统一初始化为 undefined(针对 var 声明)或暂不初始化(let/const 的暂时性死区)。
- var 声明的原始变量:创建阶段进入 VO,值设为 undefined;执行阶段才赋真实值
- let/const 声明的原始变量:创建阶段进入 TDZ(暂时性死区),直到执行到声明语句才初始化
- 函数参数接收原始值:形参在 AO 中初始化为传入的实际值(非引用),修改形参不影响实参
原始值参与表达式时的上下文影响
原始值自身无上下文,但当它出现在运算、比较或条件判断中,其行为取决于所在执行上下文的运行时规则,而非值本身:
-
"5" - 2在全局上下文或任意函数上下文中都转为数字相减,因 - 运算符强制 ToNumber 转换 -
if (x)的真假判断逻辑固定,但 x 来自哪里(全局变量?闭包捕获?解构默认值?)决定了它的实际值是否被正确初始化 -
String.prototype.trim.call(123)能成功,是因为 call 把原始数字 123 临时包装为 String 对象——这个包装发生在当前函数上下文的 AO 内部,执行完即丢弃
解构与默认值中的上下文语义陷阱
解构赋值的默认值逻辑依赖于上下文对 undefined 的判定,而 null、""、0 都不会触发默认值,这点常被忽略:
-
const { name = "guest" } = { name: null }→ name 是 null,不是 "guest" -
const { count = 0 } = { count: undefined }→ count 是 0,因为只有 undefined 才触发默认值 - 这背后是解构算法在当前上下文中检查属性是否严格等于 undefined,而不是“假值”
原型方法调用时的隐式上下文切换
原始值调用方法(如 "abc".toUpperCase())会触发临时对象包装,该包装过程发生在当前函数上下文内:
- 引擎在调用点临时创建一个 String 实例,this 指向该实例
- 方法执行完毕后,该包装对象立即销毁,不保留引用
- 因此
typeof "abc".constructor是 function,但"abc".constructor === String为 true,说明上下文里复用了原生构造函数 - 禁止修改 String.prototype,否则所有字符串调用都受影响——这是全局上下文污染,不是单个上下文问题











