__proto__ 和 prototype 深度剖析

为什么要进行深度剖析

proto 和 prototype 是一个老生常谈的话题,也是作为一个前端开发人员必须搞懂的问题,且不应该有任何的折扣,这是通往高级前端开发的必经之路和必备技能。虽然实际开发中用的并不多,但是当你学习一些新的js框架乃至自己封装一些高性能的组件时是及奇有用的。
网上的相关资料很多,讲解也是多种多样,但是至今都没有看到一篇自己满意的文章,于是在翻阅众多资料以及相关书籍之后,作者我一鼓作气,撸起袖子——就是干。

在正式进行讲解时,各位看官务必弄清楚以下两个问题。

什么是 proto(高层三中被称之为 [[Prototype]]) ? 什么是prototype

  • 初学javascript我们就知道,万物皆对象,proto__符号是用于指向someObject的原型,所有的对象都具有属性__proto
  • prototype 是 function 特有的属性,用来指向 function 的 原型

请允许我先上一张从百度搜索出来的图:

看到这里我知道你开始吐槽了,和网上看到的大部分一样,然后表示一脸懵逼
别急,接下来我会为你一一剖析每一个过程

为了配合讲解,先上一段代码,边思考边往下看(程序猿的世界里最讲道理的就是这东西了):

Function.prototype.b = 666; // Funciton 中添加属性b
Object.prototype.a = 8888; //  Object 中添加属性a

function foo() {
  this.d = 999;
}
// 构造函数创建的实例
var f1 = new foo(); // 实例 object
console.log(f1.a); // 8888
console.log(f1.b); // undefined

console.log(foo.a); // 8888
console.log(foo.b); // 666

var o1 = new Object();
console.log(o1.a); // 8888
console.log(o1.b); // undefined

console.log(Object.a) // 8888
console.log(Object.b) // 666
  • 首先,我们分别在 Function 和 Object 的原型中分别添加了属性 b 和 a
  • 然后创建了一个构造函数 foo
  • 通过 new 构建了一个新的对象

构造函数继承


接下来我们结合代码来看如下图中的关系:

var f1 = new foo(); // 实例 object
console.log(f1.a); // 8888
console.log(f1.b); // undefined

通过 new 构造出来的实例 f1 的 proto 指向了构造函数【foo】的原型, foo 的 proto 直接指向了 Object.prototype ,我们刚才手动在 Object 的 prototype 上添加了属性a。Object.prototype.a = 8888; 所以有了如下结果:

console.log(f1.a); // 8888

有因为 new 出来的 f1 仅仅是 Object 的实例,最终只能继承 Object原型上的属性,所以对于没有的属性 b 自然就是 undefined

console.log(f1.b); // undefined

函数继承


到此我们了解了构造函数实例、构造函数、以及构造函数 prototype 之间的关系,接下来,我们在身下的部分,如图所示:

console.log(foo.a); // 8888
console.log(foo.b); // 666

有图中标号为1的线,我们知道 foo 的 proto 指向 Function.prototype 所以就有了

Function.prototype.b = 666; // Funciton 中添加属性b
console.log(foo.b); // 666

根据图中的4号线的指向,Function.prototype 的 proto 指向 Object.prototype 所以就有了

Function.prototype.b = 666; // Funciton 中添加属性b
console.log(foo.a); // 8888

也就是说 foo 同时继承了 Function.prototype 和 Object.prototype 的属性

对象的继承


var o1 = new Object();
console.log(o1.a); // 8888
console.log(o1.b); // undefined

o1 为 Object 的实例, Object 的原型指向 Object.prototype,所以o1 自然而然的继承了 Object.prototype 的属性

整个图中最难以理解的部分就是 Object 和 Function.prototype 的关系了,为啥 对象又函数扯上关系了,也不知道当初祖师爷是怎么想的,既然如此,路一行代码看看就知道了。

console.log(Object.a) // 8888
console.log(Object.b) // 666

果然不出所料,Object 同时继承了 Object.prototype 和 Function.prototype 的属性

一开始,我们的代码就用代码展示了 这个经典的图中的 proto 和 prototype 之间的关系,而后有简单的结合代码做了展示,相信各位也已经看懂了,也了解 函数的实例、构造函数的实例、构造函数、函数以及对象之间的关系。在这里作者我需要向各位强调以下必须注意的知识点

  • 所有的 Object 都有 proto 属性
  • prototype 是 function 所特有的
  • 通过 new 构造出来的object,无论是 new foo() 还是 new Object() 所构造出来的 object,最终都会继承 Object.prototype
  • new foo() 的实例既可以继承 foo.prototype 也可以继承 Object.prototype
  • new Object() 只能继承 Object.prototype
  • 只有 Object 才可以继承 Function.prototype

记住以下几点,我想足够纵横 proto 和 prototype 的关系,彻彻底底的弄明白原型链之间的工种关系。测地弄明白这张图和这几行代码个人认为足够了,如果各位看官还是觉得有点吃力,好好看看 《高级程序设计第三版》PDF请自行异步这里下载 的第六章关于原型链的讲解,看完之后在回过头来看看这图,相信一定会荒原大悟。

小结


更多的干货请点击这里
react-native 实战项目学习
欢迎各位看官的批评和指正,共同学习和成长
希望该文章对您有帮助,您的鼓励和支持是我持续的最大动力

猜你喜欢

转载自blog.csdn.net/woleigequshawanyier/article/details/85338995
今日推荐