前言 🎤
__proto__ 和 prototype 两个直接让一般人去世的问题。今天就来好好研究一番。
先看两点
__proto__指向构造函数的prototypeprototype你可以认为是一个函数模版,用于存放自身的属性以及方法,以及他的上一个原型。
为什么是这样?
首先__proto__的作用是创建一个原型链,要通过__proto__,你才能不断的找到所谓的父原型。如果用代码来表示,应该是这样。
let prototype = {
//@type {prototype}
__proto__
//some methods or some property
//etc
getName:function(){}
}
可能还有人会云里雾里。其实你换一个角度想一下,他为什么叫链?举个例子,假设现在让你写一个链表,存放的数据为number,你会怎么写?一般情况下,想出来的内容应该是这样。
let Node = function(val){//prototype
this.next;// __proto__
this.val = val;// prototype content
}
let head = new Node(1)
head.next = new Node(2)
console.log(head)
是不是非常的有道理?所以,__proto__都会指向上一个prototype。而prototype中的内容,就包含了一个实例中的各种成员以及属性。
当然这个例子并不是说prototype的实现方法就是这样。这只是说明了为什么会有__proto__和prototype而已。
关➡️系
先看一张图
来源 通过这张图片,我们可以总结几点内容
- 所有
函数对象的__proto__都在Function.prototype上。 - 所有
函数对象的prototype都指向自身的prototype(废话)。 - 所有
实例对象(被new 或者其他方式)的__proto__都指向构造实例对象的函数对象的prototype(也就是构造函数的prototype) Object.prototype的__proto__为null
结合上面链表的例子,你看懂了吗?
如果可以不恰当的比喻,那么就是__proto__指向了一个模版,prototype的内容就是这个模版的内容。而且模版的内容中,也包含了上一个模版的“指针”--__proto__。
当然,这里有个特殊情况。
let f = function(){}
function f(){}
let f = new Funtion()
这三种情况所创建的内容,你必须要把他们统一称之为一个由构造函数为Function所创建都是实例对象,同时也是一个新prototype的构造函数。而js中,所有的对象的构造函数,一定在Function的链上。同样的Object,Array也都是这样。
当然,按照我的理解,你可以简单的认为。凡是可以new的东西,都是构造函数,同时也都在Function.prototype的链上。再回去看看那张图,你是不是能获得更多的启发?
同时,你还可以这么理解。
Function.prototype is class{}
Function is class.constructor
所以,所有的构造函数,包括Function自己,都在Function.prototype的原型链上。如果这句话你理解了,那么你可以自动的过滤掉我上面所说的特殊情况,js的原型链,除了Object.prototype.__proto__ === null。其他的都遵循着构造函数的__proto__的链中,一定包含着Function.prototype,没有例外。(当然...如果你直接修改f.__proto__ = null,我也是没办法拦着你的😄)。
那么现在举个小例子你看你能不能搞明白?
Number instanceOf Number === false
如果搞明白的,可以直接看结语,如果搞不明白的,甚至不知道instanceOf是怎么判定的,可以看我分析。 首先实现一个jsInstanceOf函数
/**
* @param {object} o
* @param {Contructor Function} i
*/
function jsInstanceOf(o,i){
// if typeof o != 'object'.....
let p = o.__proto__
while(p != null){
if(p == i.prototype){
return true
}
p = p.__proto__
}
return false
}
// > jsInstanceOf(Number,Number)
// false
// > jsInstanceOf(Number,Function)
// true
// > jsInstanceOf(Object,Function)
// true
// > jsInstanceOf(Function,Object)
// true
还记得上面的链表例子吗?
let Node = function(val){//prototype
this.next;// __proto__
this.val = val;// prototype content
}
你觉得Node.next === Node合理吗?
结语 👨🏫
很多人不能搞清楚为什么Object instanceOf Function === true和Function instance of Object === true。其实搞明白Function和Object其实都是构造函数后,就没那么多问题了。
所以,能真正决定一个对象功能的,是他指向的prototype。而他的__proto__则是用来找到prototype。