一、前言: 蓝本、蓝本链的象征意义
JS 中如前所述蓝本、蓝本链, 能让 JS 第一类保有PCB、承继和隐式等为数众多优点; 对蓝本、蓝本链的介绍能协助他们更深入细致自学 JS, 能让他们更快的认知 JS 承继、 new URL基本原理, 协助他们更快的PCB模块、强化标识符……
二、蓝本
2.1「表达式」中「prototype」对准「蓝本第一类」
当他们建立两个表达式时, 表达式单厢有两个预设优点 prototype, 该优点对准一个第一类, 该第一类就被称作 蓝本第一类
function fun(){} fun.prototype // 蓝本第一类2.2「第一类」中「__proto__」对准「蓝本第一类」
当表达式做为 一般表达式 展开初始化时, 该优点不能有任何人促进作用当表达式被做为 构造表达式 展开初始化 (采用 new 操作符初始化) 时, 构筑出的 示例第一类 会有两个优点 __proto__ 对准 蓝本第一类functionfun(name){ this.name = name } fun.prototype // 蓝本第一类 const obj = new fun(moyuanjun) // 表达式被做为构造表达式展开初始化obj.__proto__ ===fun.prototype // true, 示例第一类.__proto__ 对准 构造表达式.prototype2.3「蓝本第一类」中「constructor」对准「构造表达式」
蓝本第一类 预设会有两个特殊的优点 constructor, 该优点又对准了表达式本身
function fun(name){ this.name = name } fun.prototype // 蓝本第一类 constobj = newfun(moyuanjun) // 表达式被做为构造表达式展开初始化 obj.__proto__ === fun.prototype // true fun.prototype.constructor === fun // true2.4「__proto__」与「[[Prototype]]」
认真的你如果将 示例第一类 打印出, 会发现第一类中并不具有 __proto__ 优点, 恰恰相反有个特殊的 [[Prototype]] 优点, 那么这又是怎么回事呢?
__proto__ 和 [[Prototype]] 关系说明
__proto__ 并不是 ECMAScript 语法规范的标准, 它只是大部分浏览器厂商实现或说是支持的两个优点, 通过该优点方便他们访问、修改蓝本第一类遵循 ECMAScript 标准, [[Prototype]] 才是正统, [[Prototype]] 无法被直接修改、引用从 ECMAScript 6 开始, 可通过 Object.getPrototypeOf() 和 Object.setPrototypeOf() 来访问、修改 蓝本第一类简单认知: __proto__ 和 [[Prototype]] 是同两个东西, __proto__ 是非标准的, [[Prototype]] 才是标准的, 但是它们都是对准 蓝本第一类那么问题来了, 他们访问的 __proto__ 在哪里呢? 实际上它是被添加在 Object.prototype 上, 然后通过 蓝本链(后面会详细展开说明) 他们就能够访问到该优点补充:这里只是对 __proto__ 与 [[Prototype]] 优点做了简单说明, 虽然 __proto__ 是非标准的, 但是下文依然会继续采用 __proto__ 来展开演示、说明
2.5 所有非空类型数据, 都具有「蓝本第一类」
任何人 非空数据 , 本质上都是通过对应 构造表达式 构筑出来的, 所有它们都具有 __proto__ 优点, 对准 构造表达式 的蓝本第一类
所以要判断某个值其 蓝本第一类, 只需要确认该值是通过哪个 构造表达式 构筑的即可, 只要确认了 构造表达式 那么该值的 __proto__ 必然对准该 构造表达式 的 prototype
// 数字 const num = 1 // 数字是通过 Number 构筑的, 那么其蓝本第一类等于 Number.prototypenum.__proto__ === Number.prototype// true // 字符串 const str = str // 字符串是通过 String 构筑的, 那么其蓝本第一类等于 String.prototype str.__proto__ === String.prototype // true // 布尔类型 const bool = false // 布尔值是通过 Boolean 构筑的, 那么其蓝本第一类等于 Boolean.prototype bool.__proto__ === Boolean.prototype // true // Symbol const sym = Symbol(symbol) // sym 是通过 Symbol 构筑的, 那么其蓝本第一类等于 Symbol.prototype sym.__proto__ === Symbol.prototype // true // BigInt constbig = BigInt(1) // big 是通过 BigInt 构筑的, 那么其蓝本第一类等于 BigInt.prototype big.__proto__ === BigInt.prototype // true // 第一类 const obj = { age: 18 } // 第一类是通过 Object 构筑的, 那么其蓝本第一类等于 Object.prototypeobj.__proto__ === Object.prototype// true // 表达式 const fun = () => {} // 表达式是通过 Function 构筑的, 那么其蓝本第一类等于 Function.prototype fun.__proto__ === Function.prototype //true // 数组 const arr = [1, 2, 3] // 数组是通过 Array 构筑的, 那么其蓝本第一类等于 Array.prototypearr.__proto__ === Array.prototype// true2.6 补充: new 操作符做了哪些事情
建立两个新的空第一类 A挂载 蓝本第一类: 第一类 A 建立 __proto__ 优点, 并将 构造表达式 的 prototype 优点赋值给 __proto__改变 构造表达式 this 对准, 对准第一类 A得到两个新第一类一般是返回第一步建立的第一类 A但是如果 构造表达式 也返回了两个第一类 B 则返回第一类 B 否则返回第一类 A因此当他们执行
var o = new Foo();实际上执行的是:
// 1. 建立两个新的空第一类 A let A = {}; // 2. 挂载蓝本第一类: obj.__proto__ = Con.prototype; Object.setPrototypeOf(A, Con.prototype); // 3. 改变构造表达式 this 对准, 对准第一类 A letB = Con.apply(obj, args);// 4. 对构造表达式返回值做判断, 然后返回对应的值 const newObj = B instanceof Object ? res : A;三、蓝本链
根据上文, 所有非空数据, 都能通过 __proto__ 对准 蓝本第一类, 故而如果 蓝本第一类 非空, 那么必然会有 __proto__ 对准它自己的 蓝本第一类, 如此一层层往上追溯, 以此类推, 就形成了一整条链路, 一直到某个 蓝本第一类 为 null, 才到达最后两个链路的最后环节, 而 蓝本第一类 之间这种 链路关系 被称作 蓝本链 (prototype chain)
3.1 几个例子
直接建立两个第一类const obj = { age: 18 }从第一类 obj 视角来看:
obj 本质上是通过 Object 构筑出的, 那么 obj.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 蓝本链 到此结束如此得到 蓝本链(红色) 如下:
从数据上来看(看 [[Prototype]]):
从 num 视角来看
num 本质上是通过 Number 构筑出的, 那么 num.__proto__ 等于 Number.prototypeNumber.prototype 本质上是个第一类, 是通过 Object 构筑出了, 那么 Number.prototype.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 蓝本链 到此结束如此得到 蓝本链(红色) 如下:
从数据上来看(看 [[Prototype]]):
有标识符如下:
function Person(age) { this.age = age }var person = new Person(100)从第一类 person 视角来看:
person 是通过 Person 构筑出的, 那么 person.__proto__ 等于 Person.prototypePerson.prototype 是个第一类, 是通过 Object 构筑出了, 那么 Person.prototype.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 蓝本链 到此结束如此得到 蓝本链(红色) 如下:
下面他们换两个角度来思考, 站在 构造表达式 Person 视角来看:
Person 本质上是个表达式, 是通过 Function 构筑出的, 那么 Person.__proto__ 等于 Function.prototypeFunction.prototype 本质上是个第一类, 是通过 Object 构筑出了, 那么 Function.prototype.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 原型链 到此结束补充上 Person 相关 蓝本链(红色) 有:
同时, 构造表达式 Object 又是 Function 构筑出的, 那么如果从构造表达式 Object 视角来看:
Object 本质上也是个表达式, 是通过 Function 构筑出的, 那么 Object.__proto__ 等于 Function.prototypeFunction.prototype 本质上是个第一类, 是通过 Object 构筑出了, 那么 Function.prototype.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 蓝本链 到此结束补充上 Object 相关 蓝本链(红色) 有:
再有 构造表达式 Function 是个表达式, 它自己构筑了自己, 那么从构造表达式 Function 的视角来看:
Function 是个表达式, 是通过自己构造出的, 那么 Function.__proto__ 等于 Function.prototypeFunction.prototype 本质上是个第一类, 是通过 Object 构筑出了, 那么 Function.prototype.__proto__ 等于 Object.prototypeObject.prototype 的 蓝本第一类 为 null, 蓝本链 到此结束补充上 Function 相关 蓝本链(红色) 有:
小小总结
所有 蓝本链 最后单厢到 Object.prototype, 因为 蓝本第一类, 本质上就是个第一类, 由 Object 展开建立, 其 __proto__ 对准 Object.prototypeObject.prototype.__proto__ 等于 null, 所以 蓝本链 的终点必然是: Object.prototype => null3.2 蓝本链的作用
查找优点: 当他们试图访问 第一类优点 时, 它会先在 当前第一类 上展开搜寻, 搜寻没有结果时会继续搜寻该第一类的 蓝本第一类, 以及该第一类的 蓝本第一类 的 蓝本第一类, 依次层层向上搜索, 直到找到两个名字匹配的优点或到达蓝本链的末尾有标识符如下:
function Person(age) { this.age = age } Person.prototype.name = klxPerson.prototype.age =18 const person = new Person(28) person // 当前第一类: { age: 28 } person.name // klx, 取自蓝本第一类 Person.prototype person.age // 28, 取自当前第一类 person.toString() // [object Object], 取自蓝本第一类 Object.prototype person.address // undefined, 沿着蓝本链找不到 address根据标识符, 得到如下简化的 蓝本链 示意图, 在访问 person 优点时, 是按照下图链路一层层往下搜寻
如下标识符, 在示例第一类 p2 中, 屏蔽了蓝本第一类 Person.prototype 中 name 优点
function Person() {} Person.prototype.name = klx Person.prototype.age = 18 const p1 = new Person() constp2 =new Person() p2.name = myj // p2 声明 name 优点, 屏蔽蓝本第一类 Person.prototype 中 name 优点 p1.name // klx, 取自原型第一类 Person.prototype p2.name // myj, 取自示例第一类蓝本第一类 中的表达式被初始化时, this 对准是 当前第一类, 而不是表达式所在的 蓝本第一类// 1. 初始化「一般第一类」中的方法 const obj = { a: 10, name: { a: 1, printA: function(){ console.log(this.a + 1) } } } obj.name.printA()// 2, printA 表达式 this 对准表达式所在的第一类 // 2. 初始化「蓝本第一类」中的方法 function Person() { this.a = 10} Person.prototype.a =1 Person.prototype.printA = function(){ console.log(this.a + 1) } const person = newPerson() person.printA()// 11, printA 表达式 this 对准的是蓝本第一类 Person.prototype