javascript属性访问失败时返回undefined,是[[get]]内部方法遍历原型链至null仍未匹配的默认结果,而非主动返回;该行为由ecmascript规范定义,确保静默失败以提升代码健壮性。

当 JavaScript 在原型链上查找属性失败时,最终返回 undefined,这不是“主动返回”,而是整个属性访问过程自然终止后的默认结果。这个行为由 ECMAScript 规范中 [[Get]] 内部方法的执行逻辑决定,核心在于“遍历到原型链末端(null)后无匹配,且未触发任何异常或拦截”。
属性访问触发 [[Get]] 内部方法
当你写 obj.prop 或 obj['prop'],引擎实际调用的是对象的 [[Get]] 内部方法(非 JS 可见),它接收三个参数:要读取的属性键、接收者(receiver,通常为 obj 本身)、以及可选的严格模式标识。
[[Get]] 不是简单地“在当前对象查一下”,而是一套递归寻址协议,关键步骤如下:
- 先检查当前对象(即 receiver 所指对象)自身是否拥有该属性(自有属性,含可枚举/不可枚举、数据/访问器属性);
- 如果找到,直接返回其值(对访问器属性会调用
get函数); - 如果没找到,且该对象有原型(即
[[Prototype]] !== null),则把查找任务委托给其原型对象,递归调用 [[Get]]; - 如果当前对象的
[[Prototype]]是null(即到达原型链顶端,如Object.prototype的原型),且仍未找到属性,则停止查找,返回undefined。
原型链终点是 null,不是 Object.prototype
很多人误以为原型链终点是 Object.prototype,其实它的 [[Prototype]] 值是 null。这才是真正的终点:
Object.getPrototypeOf(Object.prototype) === null // true
所以完整链条是:obj → obj.__proto__ → … → Object.prototype → null。一旦 [[Get]] 沿着 [[Prototype]] 走到 null 还没匹配,就结束并返回 undefined。
这个行为与 in 操作符不同:'prop' in obj 查到 null 仍返回 false(不抛错,也不返回 undefined),因为它只关心存在性,不触发 [[Get]]。
Proxy 和 getter 会中断或改变这个流程
如果对象被 Proxy 包裹,或某个原型上有同名 getter,[[Get]] 行为会被拦截或重定义:
-
Proxy的gettrap 可以任意返回值(包括undefined),甚至抛错,完全绕过默认链式查找; - 若某级原型定义了
get prop() { return 42; },[[Get]] 在该层命中后立即调用该函数并返回结果,不再继续向上; - 若某级原型的
get prop()显式返回undefined,那结果就是undefined,但这属于主动返回,不是“查找失败”的默认行为。
没有“找不到就报错”,这是设计选择
ECMAScript 明确规定:属性读取失败不抛 ReferenceError(那是变量未声明时的事)。这种静默返回 undefined 的策略,让代码更健壮,比如:
if (user.profile?.avatar) { ... } // 可选链依赖此机制
如果每次查不到都 throw,很多防御性判断就无法简洁表达。当然,这也带来隐患(如拼写错误难发现),所以开发中常配合 TypeScript 或 ESLint 来弥补。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











