原型是 javascript 实现方法复用的一种手段, 在当前操作者调用一个属性或者方法的时候,如果当前的操作者没有此属性或者方法,则去它的原型上找,如果他的原型上也找不到,那就再去它的原型上的原型上找属性或者方法,如此循环,找到为止或者最顶层原型为 null 则停止
原型链的查找
我们先来看一段如下代码,我们定义了一个干净的空对象,但是却在这个 obj 上调用到了 toString 和 valueOf 方法, 你可能在想,这是内置的呗,只要使用便是,但是它是内置到哪里的呢?
const obj = {}; // 当前操作者 是 obj
const { log } = console;
log("obj.toString(): ", obj.toString()); // log: [object Object]
log("obj.toString(): ", obj.valueOf()); // log: {}
为了实现共用代码的复用,javascript 会将复用的一些功能添加到原型上,而原型又有原型,以此便形成了原型链。根据原型链的查找规则,可在看似空空的操作者上也可以去调用原型链上的属性或者方法。
tips: 原型链就像一个公司的职责一样,你没有权限的去做的事情,只需要给你上级要即可,如果你的上级没有这个权限,那你的上级也会去找 ta 的上级找,直到获取了权限或者所有人都没有权限为止便结束
原型的引用变量及其关系
- 每个 function 声明的函数 都有 prototype (显式原型, 头函数没有此变量)
- 每个 实例对象 都有
__proto__(隐式原型)- 对象的隐式原型指向它的构造函数的显示原型的引用地址
- 一般只会操作显示原型对象
每个 function 声明的函数都有显示原型对象 prototype
// 如下代码可以建议在 浏览器的 console 运行看一下
var pureArrowFn = () => {}; // 箭头函数没有 prototype
var funArrow = function () {};
function func() {}
const { dir } = console;
dir(pureArrowFn.prototype); // log: undefined
dir(funArrow.prototype); // log: funArrow.prototype 的值
dir(func.prototype); // log: funArrow.prototype 的值
说明: 在定义函数的时候,会给函数名,或者接受 function 定义的变量名新增 prototype 属性,默认值是一个空对象
tips: 因为每一个 function 定义的函数,其实都是 Function 的实例,因此 每个函数也存在 __proto__ 属性, 即每个函数的 __proto__ 指向 Function.prototype,
对象的隐式原型对象 __proto__
__proto__并不是语言本身的特性,这是许多浏览器的 JS 引擎提供的,不建议在生产环境中使用,但是可以使用 Object.getPrototypeOf(obj) 来获取 obj 的原型
对象的 __proto__ 指向其构造函数的原型,在浏览器中直接访问 obj 的 __proto__ 属性,可以获取到如下图所示信息,可以看到空对象 obj 上的 __proto__ 是存在 toString、valueOf 等方法的
// 定义一个 对象字面量 obj,他的构造函数是 Object
var obj = {};
const { dir, log } = console;
dir(obj.__proto__);
// 验证 obj.__proto__ 是不是指向 obj 的构造函数 Object
log(obj.__proto__.constructor.name === "Object"); // log: true
tips: 所有对象的构造函数都是 Object, Object 也存在 __proto__ 属性
对象的隐式原型指向它的构造函数的显示原型的引用地址
var obj = {};
// 验证对象的 __proto__(隐式原型) 和 其构造函数的 prototype(显示原型)是否共享同一片内存地址
var { log } = console;
log(obj.__proto__ === Object.prototype); // log: true
__proto__ 和 prototype 的关系图:
小结:
- 实例对象的
__proto__指向其构造函数的 显示原型 - 构造函数的 constructor 指向构造函数本身
- Object 是 Function 的实例, 或者说 Function 是 Object 的构造函数
- 所有函数都是 Function 的实例(包含 Function)
- Object 的原型是原型链的尽头 Object.prototype.
__proto__为 null