__proto__ 是 [[prototype]] 内部槽的外部映射,本质为可读写的自有属性指针,非存取描述符;存取描述符(get/set)则属 object.defineproperty 管理的属性特性体系,两者机制正交。

__proto__ 属性不是描述符,更不是“隐式存取描述符”——这个说法混淆了 JavaScript 中两个完全不同的机制:原型链查找机制 和 属性描述符(Descriptor)协议。
我们来一层层厘清:
魔搭GPT(ModelScopeGPT)是一款AI视频创作工具,阿里达摩院推出的大小模型协同的智能助手,具备作诗、绘画、视频生成、语音播放等多模态能力。
__proto__ 是什么?——一个内部指针,不是属性描述符
-
__proto__是对象的一个可读写的自有属性(尽管已被标准标记为“过时”,推荐用Object.getPrototypeOf()/Object.setPrototypeOf()),它的值是一个对象(或null)。 - 它的物理本质是:引擎内部
[[Prototype]]内部槽(internal slot)的暴露接口。ECMAScript 规范中定义每个普通对象都有一个[[Prototype]]槽,用于原型链查找;__proto__只是浏览器/JS引擎(如 V8)为调试和兼容提供的非标准但广泛实现的访问通道。 - 它不参与
Object.defineProperty的描述符系统,也不触发__get__/__set__—— 它本身就是一个普通数据属性(早期 V8 甚至用 getter/setter 实现过,但那是实现细节,不是语义)。
✅ 正确理解:
__proto__是[[Prototype]]的外部映射,作用是让 JS 开发者能读写对象的原型链接关系。
❌ 错误理解:把它当作类似 Python 描述符那样的“拦截属性访问的协议机制”。
那什么是“存取描述符”?——和 __proto__ 完全无关
- 存取描述符(accessor descriptor)指用
get/set函数定义的属性,例如:const obj = { get foo() { return 'bar'; }, set foo(v) { console.log(v); } }; - 这类属性的访问会触发对应的
get或set函数,属于Object.defineProperty所管理的属性特性(property attributes)体系。 - 它们存在于对象自身的属性表中,与原型链查找是正交机制:即使你在原型上定义了一个
get foo(),实例访问foo时仍会走原型链找到它,但触发的是那个get函数——这和__proto__本身毫无关系。
为什么容易混淆?——因为都涉及“访问”和“间接性”
| 特性 | __proto__ |
存取描述符(get/set) |
|---|---|---|
| 所属机制 | 原型链(inheritance) | 属性定义(property definition) |
| 触发时机 | 访问不存在于自身的属性时自动向上查原型 | 访问已定义在当前对象或原型上的存取器属性时立即执行函数 |
| 是否可配置 |
__proto__ 是自有属性,可被 delete(但不推荐) |
configurable 控制能否删除或重定义 |
是否参与 in / hasOwnProperty
|
__proto__ 自身是自有属性,"__proto__" in obj 为 true
|
get foo() 在 obj 上定义,则 "foo" in obj 为 true,但 obj.hasOwnProperty('foo') 取决于是否在自身定义 |
补充:constructor 和 prototype 也非描述符
-
Function.prototype.constructor、Object.prototype.toString等,都是普通数据属性或方法,放在原型对象上供继承使用。 - 它们之所以“看起来像魔法”,是因为原型链自动提供访问路径,而非靠描述符拦截。
所以结论很明确:
-
__proto__没有“隐式存取描述符”的物理本质; - 它是
[[Prototype]]内部槽的浅层代理,本质是对象间的一条单向引用链指针; - 真正的存取控制,靠的是
get/set描述符,它们独立存在、显式定义、不依赖原型链。
理解这点,才能避免把“原型继承”和“属性访问拦截”混为一谈。










