奇奇怪怪的原型链

378 阅读3分钟

话不多说,下面这段代码的结果是啥

const obj = {name:'obj'}; 
console.log(
  obj.__proto__.constructor 
  === 
  obj.__proto__.constructor.__proto__.__proto__.constructor
) 

握草,这啥?这能有结果?

还是先上一段熟悉的,下面这段代码的打印结果想必帅哥镁铝都应该知道吧,

Object.prototype.Flag = '一个标记'
function People(name) { //构造函数
  this.name = name
}

People.prototype.sleep = '有睡觉的本领' // 为 People 的原型上添加属性

const tom = new People('tom')

console.log(tom.__proto__ === People.prototype)
console.log(tom.Flag)

很明显,打印的结果为

image.png

因为 tom.proto 和 People.prototype 都指向同一处,就是 People 的原型(People.prototype),而且 People 的原型 也含有私有属性 proto 指向 Object.prototype 所以 man 的实例也能打印出 Flag 标记,来看看它的原型链(下图): image.png

我们要打印 tom.Flag tom 没有,他会沿着原型链向上找到 People.prototype,没有则继续向上找,有则停止(如果到 null 还没找到则会返回 undefined) ,这就是原型链查找的过程,好,根据上述示例,我来引入一个问题一,如果在 tom 这更改这个标记,结果是啥。

问题1:下面的打印结果是:

Object.prototype.Flag = '一个标记'
function People(name) { //构造函数
  this.name = name
}

People.prototype.sleep = '有睡觉的本领' // 为 People 的原型上添加属性

const tom = new People('tom') 
console.log(tom.Flag) // '一个标记'
tom.Flag = 'tom的标记'

console.log(tom.Flag) 
console.log(Object.prototype.Flag) 

哎哎,偏题了,拉回来,不过也算复习下,我们继续来看开头的这段代码打印的结果是啥

const obj = {name:'obj'}; 
console.log(
  obj.__proto__.constructor 
  === 
  obj.__proto__.constructor.__proto__.__proto__.constructor
) 

这次我们来换张图,

image.png

你可以把我们刚才讲的看做我圈出来的这部分

image.png

有助于你理解这张图,现在要看其他部分,根据题目的第一部分,他用隐式创建了一个对象 const obj = {name:'obj'};  可以将 obj 看做 上图的 o1 在根据他的第一个要打印的第一个值 obj.__proto__.constructor 在图上可以找到,就是 Object.prototype 要的打印的第二个值obj.__proto__.constructor.__proto__.__proto__.constructor 你仔细找找,是不是经过 Function.prototype 又绕回去了,又是 Object.prototype ,那他量不就相等了么。好吧大无语事件,看了这么长时间看了个寂寞。

那他两既然相等, 那就是说.....................

那可以在控制台一直这样点下去,每经过一个这个 __proto__.__proto__.constructor 他两就相等,就类似于这样

image.pngimage.png

他两形成一个环,只要你一直点他就一直有。

拉回来,既然 obj.__proto__.constructor.__proto__.__proto__.constructo 即然他形成了环,但为什么会在他们三个间形成环(对象的构造函数,对象的原型,函数的原型),为了更好的理解,我把他强加到我们上文的第一个例子了,虚线是新加的。 image.png 先来看下虚线框右边的 function 构造函数这块 image.pngimage.png

好,接下来震惊三联

震惊一:函数的原型 proto 指向对象的原型。

震惊二:对象的构造函数 proto 指向函数的原型

震惊三:函数的原型链最终也会到达--> Object.prototype --> null,

震惊三足够能说明为啥好多人都认为 js 是万物基于对象,那你咋不说对象还是由函数构造的(狗头保命) 哎我也解释不清楚,反正 js 就是这么神奇,可以理解我函数和对象相辅相成,没有谁基于谁。

还不信? image.png

console.log(Object.constructor instanceof Function); // true
console.log(Function.constructor instanceof Function); //true

这下应该没问题了。

好,那个问题一的答案是

Object.prototype.Flag = '一个标记'
function People(name) { //构造函数
  this.name = name
}

People.prototype.sleep = '有睡觉的本领' // 为 People 的原型上添加属性

const tom = new People('tom') 
console.log(tom.Flag) // '一个标记'
tom.Flag = 'tom的标记' 
/*
	并不会改变 Object.prototype 上的 Flag,因为属性访问到 tom.Flag 为 undefined 后并不会向上找,
  因为有赋值操作符,覆盖 undefined ,最终返回具有该属性则停止查找。
*/

console.log(tom.Flag) //'tom的标记'
console.log(Object.prototype.Flag) //'一个标记'

这块还有很多知识,在完善吧,如果有错请大佬回复。