摘要:所以,在每个构造函数都会有一个属性,指向一个对象作为这个构造函数构造出来的新对象的原型。那么根据上面第二条事实,每个函数也会有指向它的构造函数的。而这个构造函数的函数就是,中的所有函数都是由构造出来的。
“__proto__”
JavaScript是一个面向对象语音,即一切皆对象。
那么怎么生成对象?在Java的世界里,对象是由类(Class)实例出来的,通俗地说,就是将事物抽象成一个模具,用这个模具(类)生产出一个个具体的实物(对象)。
可是JS中没有类这个概念,有的是“原型”,对象是由原型衍生出来的。通俗地说,在JS的世界里,“原型”并不是一个模具,而是一个具体的实物(对象)。所有对象都是由另一个对象衍生出来的,而这个被衍生的对象就是所谓的“原型对象”。
每一个对象自动生成一个属性:__proto__,这个属性是一个引用对象,其指向这个对象的“原型对象”。
Talk is cheap, show me the code! 咱们来看看代码:
var obj = {}; console.log(obj);
咱们将__proto__展开看看:是一些默认方法。
你一定会发生这个__proto__对象中也有一个__proto__对象,正如我们刚才说的,每个对象都有一个__proto__属性指向它的原型对象。我们打印一下这个__proto__中的__proto__:
console.log(obj.__proto__.__proto__); //--> null
结果是null,说明已经到了顶层原型对象。obj是用大括号{}定义的,obj的原型对象自然是JS的顶层对象。
咱们再看一端代码,加强下理解:
var parent = { name : "parent" }; var child = { name : "child", __proto__ : parent }; var subChild = { name : "subChild", __proto__ : child } console.log(subChild);
subChild.__proto__ --> child
child.__proto__ --> parent
parent.__proto__ --> 顶层原型对象
上面我们说到,每一个对象都包含一个__proto__,指向这个的对象的“原型”。
类似的事情是,每一个函数都包含一个prototype,这个prototype对象干什么的了?
咱们看看如下代码,用构造函数来创建一个对象(上面是用字面量的形式创建对象)。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__);
试想想,这个foo对象的__proto__会指向什么?
一个包含constructor属性的对象?看不太懂没关系,把函数Foo的prototype属性打印出来,对比一下就知道了。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__); console.log(Foo.prototype); console.log(foo.__proto__ === Foo.prototype);
原来,new出来的对象foo的__proto__就只指向函数Foo的prototype。
foo.__proto__ --> Foo.prototype
JS这么设计有何意义了?回忆下上面说的,在JS的世界中,对象不是根据类(模具)创建出来的,而是从原型(另一个对象)衍生出来的。
当我们执行new操作创建一个新的对象时,先不深入new操作的具体实现,但有一点我们是肯定的——就是为新对象的__proto__指向一个原型对象。
就刚才这段代码
function Foo(){}; var foo = new Foo();
foo.__proto__到底要指向谁了?你怎么不能指向Foo这个函数本身吧,虽然函数也是对象,这个有机会会详细讲。但如何foo.__proto__指向Foo固然不合适,因为Foo是一个函数,有很多逻辑代码,foo作为一个对象,继承逻辑处理没有任何意义,它要继承的是“原型对象”的属性。
所以,每个函数会自动生成一个prototype对象,由这个函数new出来的对象的__proto__就指向这个函数的prototype。
foo.__proto__ --> Foo.prototype
说了这么多,感觉还是没完全说清楚,不如上一张图。我曾经参考过其他网友的图,但总觉得哪里没说清楚,所以我自己画了一张图,如果觉得我的不错,请点个赞!(老子可是费了牛劲才画出来)。
(点击可放大)
咱们就着这张图,记住如下几个事实:
1. 每个对象中都有一个_proto_属性。
JS世界中没有类(模具)的概念,对象是从另一个对象(原型)衍生出来的,所以每个对象中会有一个_proto_属性指向它的原型对象。(参考左上角的那个用字面量形式定义的对象obj,它在内存中开辟了一个空间存放对象自身的属性,同时生成一个_proto_指向它的原型——顶层原型对象。)
2. 每个函数都有一个prototype属性。
“构造函数”为何叫构造函数,因为它要构造对象。那么根据上面第一条事实,构造出来的新对象的_proto_属性指向谁了?总不能指向构造函数自身,虽然它也是个对象,但你不希望新对象继承函数的属性与方法吧。所以,在每个构造函数都会有一个prototype属性,指向一个对象作为这个构造函数构造出来的新对象的原型。
3. 函数也是对象。
每个函数都有一些通用的属性和方法,比如apply()/call()等。但这些通用的方法是如何继承的呢?函数又是怎么创建出来的呢?试想想,一切皆对象,包括函数也是对象,而且是通过构造函数构造出来的对象。那么根据上面第二条事实,每个函数也会有_proto_指向它的构造函数的prototype。而这个构造函数的函数就是Function,JS中的所有函数都是由Function构造出来的。函数的通用属性与方法就存放在Function.prototype这个原型对象上。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/78272.html
摘要:实例可以通过代理来找到它,并用来检测其构造函数。经典继承图这也是通过构造函数来创建对象,但是在这一系列的对象和实例之间我们的焦点是放在原型链上。尽管,但构造函数的属性并不是对象自己的属性,它实际上是通过寻找原型链获得的,即所指向的地方。 继承是面向对象编程语言的一大核心功能点,虽然JavaScript并不是一门真正意义上的面向对象的编程语言,但也通过某种手段实现了继承这一功能,最常见的...
摘要:了解中原型以及原型链只需要记住以下点即可对象都有属性,指向构造函数的构造函数函数都有属性,指向构造函数的原型对象的内置构造函数可知所有的构造函数都继承于甚至包括根构造器及自身。 了解JavaScript中原型以及原型链只需要记住以下2点即可 对象都有__proto__属性,指向构造函数的prototype 构造函数函数都有prototype属性,指向构造函数的原型 1、对象的__p...
摘要:而作为构造函数,需要有个属性用来作为以该构造函数创造的实例的继承。 欢迎来我的博客阅读:「JavaScript 原型中的哲学思想」 记得当年初试前端的时候,学习JavaScript过程中,原型问题一直让我疑惑许久,那时候捧着那本著名的红皮书,看到有关原型的讲解时,总是心存疑虑。 当在JavaScript世界中走过不少旅程之后,再次萌发起研究这部分知识的欲望,翻阅了不少书籍和资料,才搞懂...
摘要:深入理解原型与继承看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解。 深入理解:JavaScript原型与继承 看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解。 首先JavaScript是一门基于原型编程的语言...
摘要:原文链接关于的原型和原型链,看我就够了一参考链接闯关记之原型及原型链之原型与原型链一篇文章带你理解原型和原型链彻底理解原型链一的默认指向图解和的三角关系原型和原型链三张图搞懂的原型对象与原型链 温故 创建对象的三种方式 通过对象直接量 通过new创建对象 通过Object.create() js中对象分为两种 函数对象 普通对象 仔细观察如下代码 function Foo(na...
摘要:在创建对象不论是普通对象还是函数对象的时候,都有一个叫做的内置属性,用于指向创建它的构造函数的原型对象,也就是。因为一个普通对象的构造函数所以原型链原型链的形成是真正是靠而非。参考文章最详尽的原型与原型链终极详解,没有可能是。 【前端芝士树】Javascript的原型、原型链以及继承机制 前端的面试中经常会遇到这个问题,自己也是一直似懂非懂,趁这个机会整理一下 0. 为什么会出现原型和...
阅读 1774·2021-11-18 10:02
阅读 3507·2021-11-16 11:45
阅读 1755·2021-09-10 10:51
阅读 2064·2019-08-30 15:43
阅读 1355·2019-08-30 11:23
阅读 1460·2019-08-29 11:07
阅读 1873·2019-08-23 17:05
阅读 1342·2019-08-23 16:14