Prototype和_proto_的区别
- Prototype属性(原型对象)。是函数(Function)独有的属性,非函数类对象没有这个属性。作用是,作为一个“公共仓库”,用来放置希望所有实例共享的属性和方法。
- _proto_属性(隐式原型指针)。JavaScript 中的每一个对象(包含函数、数组、实例等)都有。作用是,指向创建该对象的构造函数的 prototype。它就是对象用来“向上查找”的连接线。
一个函数对象拆解后的实际样子
要彻底搞懂一个函数对象在内存和浏览器控制台里的完整拆解结构,我们可以将它划分为 4 大核心板块。
在 Chrome 控制台中运行 console.dir(Foo) 并展开后,你能看到它的全部内部组成:
function Foo(name) {
this.name = name;
}
Foo.prototype.sayHello = function() {};
Foo.myStaticMethod = function() {}; // 静态方法
console.dir(Foo);函数对象的 4 大结构板块
板块 1:函数自身的常规属性(静态属性与方法)
这是挂载在函数本身上的属性。当你把函数当成普通对象使用时(例如 Foo.myStaticMethod = ...),这些属性直接存在于函数自身。
name:函数名(如"Foo")。length:形参个数(如1)。- 自定义静态属性/方法:例如
myStaticMethod、Array.isArray、Object.keys等。
板块 2:prototype(显式原型板块 —— “供实例调用的共享仓库”)
这个板块专门负责给由 new Foo() 创建出来的实例对象提供共享的方法和属性。
- 主要内容:
- 自定义共享方法/属性:例如
sayHello,所有实例共享此方法。 constructor(构造器指针):默认存在,反向指回函数Foo本身(Foo.prototype.constructor === Foo)。[[Prototype]](原型的原型):Foo.prototype本身也是一个普通对象,所以它也有自己的[[Prototype]],指向Object.prototype。
- 自定义共享方法/属性:例如
板块 3:[[Prototype]](隐式原型板块 —— “函数自身的继承通道”)
这是函数自身作为对象所拥有的原型,指向 Function.prototype。因为函数本身也是由 JavaScript 的内置构造函数 Function 创建的。
- 主要内容:
- 内置函数方法:
call()、apply()、bind()、toString()等。你能在任何函数上直接调用Foo.call(),就是从这个板块里继承来的。 constructor:指向Function构造函数。[[Prototype]]:指向Object.prototype(原型链继续向上查找)。
- 内置函数方法:
板块 4:内部槽 / 隐式作用域(引擎私有板块)
控制台中以 [[...]] 双方括号包裹的内容,属于 JavaScript 引擎内部维护的私有属性。
[[Scopes]]:函数的作用域链(包含了函数定义时的闭包Closure、全局作用域Global等)。[[FunctionLocation]]:源代码中该函数定义的文件和行号位置。
控制台展开结构对照表
在 Chrome / Edge 控制台里展开 console.dir(Foo),对应结构如下:
| 板块名称 | 在控制台中的显示 | 内容是什么 | 谁会用到它 |
| 自身属性 | name, length, myStaticMethod | 函数名、形参个数、静态属性/方法 | 函数自身(如 Foo.myStaticMethod()) |
prototype 板块 | prototype | sayHello, constructor: ƒ Foo(), [[Prototype]]: Object | new Foo() 生成的实例 |
[[Prototype]] 板块 | [[Prototype]]: ƒ () | call(), apply(), bind(), constructor: ƒ Function() | 函数 Foo 自身 |
| 作用域与元数据 | [[Scopes]], [[FunctionLocation]] | 闭包变量(Closure)、环境上下文、代码源码位置 | JS 执行引擎 |
代码验证(一秒分清两个 Prototype)
JavaScript
// 1. 查看 Foo 给【实例】准备的共享仓库 (板块 2)
console.log(Foo.prototype.sayHello); // ƒ () {}
// 2. 查看 Foo 【自己】调用的函数能力 (板块 3)
console.log(Foo.call); // ƒ call() { [native code] }
// 验证:Foo 的 [[Prototype]] 就是 Function.prototype
console.log(Object.getPrototypeOf(Foo) === Function.prototype); // true