“必懂”的`__proto__`,“必懂”的`prototype`

时间:2021-1-8 作者:admin

原文链接 nishuzumi.github.io/2020/11/08/…

前言 🎤

__proto__prototype 两个直接让一般人去世的问题。今天就来好好研究一番。

先看两点

  • __proto__指向构造函数的prototype
  • prototype你可以认为是一个函数模版,用于存放自身的属性以及方法,以及他的上一个原型。

为什么是这样?
首先__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 === trueFunction instance of Object === true。其实搞明白FunctionObject其实都是构造函数后,就没那么多问题了。
所以,能真正决定一个对象功能的,是他指向的prototype。而他的__proto__则是用来找到prototype

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。