概念区分
其实说 proto 并不准确,确切的说是对象的 [[prototype]] 属性,只不过在主流的浏览器中,都用 proto 来代表 [[prototype]] 属性,因为 [[prototype]] 只是一个标准,而针对这个标准,不同的浏览器有不同的实现方式。在 ES5 中用 Object.getPrototypeOf 函数获得一个对象的 [[prototype]]。ES6 中,使用 Object.setPrototypeOf 可以直接修改一个对象的 [[prototype]]。为了方便,我下面的文章用 proto 来代表对象的 [[prototype]]。
而 prototype 属性是只有函数才特有的属性,当你创建一个函数时,js 会自动为这个函数加上 prototype 属性,值是一个空对象。所以,函数在 js 中是非常特殊的,是所谓的一等公民。
必须明确
万物皆对象
在 JS 里,万物皆对象。方法(Function)是对象,方法的原型 (Function.prototype) 是对象。因此,它们都会具有对象共有的特点。
即:对象具有属性 __proto__ ,可称为 隐式原型 ,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
方法 (Function)
方法这个特殊的对象,除了和其他对象一样有上述 proto 属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做 constructor,这个属性包含了一个指针,指回原构造函数。

如上图所示,person1、person2 都是对象,对象具有 proto 属性,此隐式原型指向构造此对象的构造函数 Person 的原型 Person.prototype。
方法 Person 也是对象,他有自己特有的属性 prototype(原型属性),这个属性指向的对象,包含有所有实例共享的属性和方法(也称为原型对象),此原型对象也有一个属性 constructor,constructor 属性包含一个指针指向原构造函数 Person。
其实,大家一旦理解了这张图,也就差不多理解了 proto 和 prototype,如果一时还没彻底明白,我们接下来看代码,结合代码再来看这张图,你就会豁然开朗。
原型链
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是 原型链 的概念
原型链的尽头是 Object.prototype
prototype 描述的是原型对象,它是一个实实在在的对象,__proto__ 是用来描述对象间的关联关系的,最终会指向一个 prototype 原型对象
- 原型对象的原型链
__proto__指向顶端的 Object.prototype - 构造函数的原型链
__proto__会首先指向 Function.prototype,如 function f (){}, Array(),Object()等
只有函数存在 prototype 属性,对象的 prototype 属性为 undefined
Function.__proto__ 和 Object.__proto__ 都是 Function.prototype
参考:走到原型链的尽头_河鲜森的博客-CSDN博客_原型链的尽头
实践检验
proto 和 prototype 概要(隐式原型与原型对象)

上图,可以看出:
构造函数 Person()
构造函数的原型属性 Person.prototype 指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是 person1,person2)都可以共享这些方法(sayName)。

原型对象 Person.prototype
Person.prototype 保存着实例共享的方法(sayName),有一个指针 constructor 指回构造函数。

实例
person1 和 person2 是 Person 这个对象的两个实例,这两个对象也有属性 proto,指向构造函数 Person 的原型对象,这样子就可以像上面【1】所说的访问原型对象的所有方法。这也就是为什么 person1、person2 都可以访问 Person 的原型对象 Person.prototype 的 sayName 方法。
构造函数 Person() 除了是方法,也是对象,它也有 proto 属性,指向谁呢?
指向它的构造函数的原型对象,函数的构造函数是 Function,因此这里的 proto 指向了 Function.prototype。也就是上上图中打印的 Person.proto: f(){native code}.
其实除了 Person(),Function()、Object() 也是一样的道理。
原型对象也是对象啊,它的 proto 属性,又指向谁呢?
同理,指向它的构造函数的原型对象,也就是说Function.prototype 对象的 proto 属性指向 Object.prototype。
最后,Object.prototype 的 proto 属性指向 null。如下图所示:

函数 Person 既有 proto 隐式属性,也有 prototype 原型对象。那么一般对象有没有 prototype 属性呢?我们继续看下面案例。
函数特有 prototype 属性,对象无
整理:实例,构造函数,原型对象,原型链,js指针,prototype和__proto__需要反复记忆的公式 - 掘金

由此,可见对象并不具有 prototype 属性,只有函数才有 prototype 属性。
最后,再通过下列代码帮助大家进一步理解最开始那张图。

Array.prototype.prototype === undefined
Function.prototype.prototype === undefined
Object.prototype.prototype === undefined
Array.prototype.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null总结
【1】对象有属性 proto,指向该对象的构造函数的原型对象。
【2】方法除了有属性 proto,还有属性 prototype,prototype 指向该方法的原型对象。
转载声明
转载自:JS里的__proto__和prototype到底有什么区别?