[我的理解]Javascript的原型与原型链
一、原型与原型链的定义
- 原型:为其他对象提供共享属性的对象
注:当构造器创建一个对象,为了解决对象的属性引用,该对象会隐式引用构造器的"prototype"属性。程序通过constructor.prototype可以直接引用到构造器的"prototype"属性。并且添加到对象原型里的属性,会通过继承与所有共享此原型的对象共享。
- 原型链:每个由构造器创建的对象,都有一个隐式引用(叫做对象的原型)链接到构造器的"prototype"属性。再者,原型可能有一个非空隐式引用链接到它自己的原型,以此类推,这叫做 原型链
二、ES5中的Function与Object类型
理解Function与Object类型的之间的关系,对我们理解原型和原型链有很重要的帮助。
var fn = Function; console.log("fn的原型:" + fn.prototype); console.log("fn的原型链:" + fn.__proto__); console.log("fn的原型等于fn的原型链:" + ( fn.prototype === fn.__proto__ ) ); console.log("fn的原型的原型链:" + fn.prototype.__proto__); var obj = Object; console.info("obj的原型:" + obj.prototype); console.info("obj的原型链:" + obj.__proto__); console.info("obj的原型不等于obj的原型链:" + (obj.prototype === obj.__proto__)); console.info("obj的原型的原型链:" + obj.prototype.__proto__);
输出结果如下:
fn的原型:function () {} fn的原型链:function () {} fn的原型等于fn的原型链:true fn的原型的原型链:[object Object] obj的原型:[object Object] obj的原型链:function () {} obj的原型不等于obj的原型链:false obj的原型的原型链:null
根据输出结果我们不难看出,Function与Object存在相互引用的关系,以及其他特点总结如下:
- Function.prototype.proto === Object.prototype:Function的原型的原型链等于Object的原型
- Function.proto === Object.proto:Function与Object的原型链是相等的
- Function.proto === Function.prototype:Function的原型等于Function的原型链,在ECMAScript5.1的规范中是如此说明的:Function的prototype是一个函数对象,他内部的[[prototype]]属性值是标准内置的Object的prototype对象。
- Object.prototype.proto === null:Object的原型的原型链为null
关系图:
- Function的prototype的__proto__是引用的Object的prototype,这是Function的原型的原型链
- 而Object的__proto__是引用了Function的prototype的。
2.1、其他原生类型
原生类型大致可以分两类,一类是继承于Function的,另一类是继承于Object。
- 继承于Function类型:String、Number、Boolean、Array、Date、RegExp、Error等,他们的__proto__(原型链)都指向了Function,而他们的prototype是各自类型的标准内置对象,这也就证明他们的prototype是继承于Object的,所以prototype.__proto__指向Object的prototype。
- 继承于Object类型:Math、JSON等。因为是对象,所以没有构造函数,也没有自己的内置原型对象(prototype属性)。但还是有原型链的,他的__proto__指向Object的prototype。
2.2、总结
- Function是函数(类)的基础原型
- Object是对象的基础原型
- 运行时创建一个对象,会将构造器的prototype属性引用复制给对象的__proto__上,这里的创建一个对象,只能是new方式。
- 用function关键字定义的类,做为Function类型的实例他本身有一个原型链(本身继承于Object),另外通过new创建的实例对象也有属于自己的原型链(prototype到__proto__的转换)。
三、实现继承(原型继承)
前面描述了Function、Object和其他原生类型的关系,在这里我们深入了解Function对象的类特性,这里我们使用function这个类,他是Function的实例,拥有Function类型的所有方法。
3.1、ES5.1
function Parent(){this.name = 'parent'; } Parent.prototype.getName = function(){console.log(this.name); }function Child(){Parent.call(this); //在this对象上增加属性this.cName = 'child'; } Child.prototype = Parent.prototype; //复制parent的prototype所有的内容,包含构造器 Child.prototype.constructor = Child; //恢复构造器为子类,不恢复也不影响其newvar _child = new Child();
实现继承的步骤:
- Parent的prototype赋值给Child的prototype,使其Child拥有Parent的原型方法或属性(子类与父类的prototype进行合并)
- 将Child.prototype.constructor指向Child函数,因为constructor是指向其构造器的方法,被Parent赋值后,其实是指向了Parent的构造器,所以需要改回来。
- 在Child的构造器中用Call执行Parent的构造器,实例构造器的继承执行(顺序执行父类、子类的构造函数)。
总结:
- 原型的继承实际上是共享原型上的属性和方法,所以更改基类原型上的属性和方法会影响到子类。但构造器中对this做的绑定则是实例独立的。
- function关键字定义的类(Parent、Child)的__proto__都是指向function的构造函数
- function关键字定义的类所有prototype的__proto__都是指向了Object的prototype。
3.2、ES2015(ES6)
在es6中实现继承就相当的简单了,不需要像es5中那么步骤来实现,继承实现如下:
class Parent {constructor(){this.name = 'parent';}getName(){console.log(this.name);} } class Child extends Parent {constructor(){super();this.cName = 'child';} }var _child = new Child();
- Class的__proto__指向父类的定义,包含构造函数。
- Class的prototype.__proto__是指向父类的prototype,表示方法的继承。
四、产生的改变
- ES5中用Function实现面向对象,而ES6提供了Class。
- ES6的Class对原型与原型链更加规范化。
- ES6提供了操作__proto__对象的方法,分别如下:
- Object.setPrototypeOf(obj,protype):设置对象的__proto__(原型对象
- Object.getPrototypeOf(obj):读取对象的__proto__(原型对象)
- ES5中可以直接对__proto__赋值,但不建议这样使用。
- ES5中对子类的prototype进行赋值后,还需要重定向prototype.constructor到子类的构造函数。
转载于:https://www.cnblogs.com/cqhaibin/p/6624128.html
[我的理解]Javascript的原型与原型链相关推荐
- 深入理解Javascript中构造函数和原型对象的区别
在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor) ...
- 深入理解JavaScript执行上下文与作用域链
文章目录 前言 一.执行上下文 1.类型 2.生命周期 2.1.创建变量对象 2.2.this绑定 2.3.创建作用域链 总结 前言 只有理解了执行上下文与作用域链,才能更好地理解JavaScript ...
- 深入理解JavaScript this
this是什么?做什么?指向是什么? 函数中this调用:this----->window 方法中this调用:this----->当前对象(嗲用方法的对象) 构造函数中this调用:th ...
- 如何理解JavaScript原型
Javascript的原型总会给人产生一些困惑,无论是经验丰富的专家,还是作者自己也时常表现出对这个概念某些有限的理解,我认为这样的困惑在我们一开始接触原型时就已经产生了,它们常常和new.const ...
- 深入理解 JavaScript 原型
前言 原型,作为前端开发者,或多或少都有听说.你可能一直想了解它,但是由于各种原因还没有了解,现在就跟随我来一起探索它吧.本文将由浅入深,一点一点揭开 JavaScript 原型的神秘面纱.(需要了解 ...
- 深入理解javascript原型和闭包(6)——继承
为何用"继承"为标题,而不用"原型链"? 原型链如果解释清楚了很容易理解,不会与常用的java/C#产生混淆.而"继承"确实常用面向对象语言 ...
- 深入理解javascript原型和闭包(16)——完结
之前一共用15篇文章,把javascript的原型和闭包. 首先,javascript本来就"不容易学".不是说它有多难,而是学习它的人,往往都是在学会了其他语言之后,又学java ...
- 深入理解JavaScript系列(5):强大的原型和原型链
前言 JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型. 虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大.实 ...
- 深入理解javascript原型和闭包(17)——补this
本文对<深入理解javascript原型和闭包(10)--this>一篇进行补充,原文链接:http://www.cnblogs.com/wangfupeng1988/p/3988422. ...
- 深入理解javascript原型和闭包(3)——prototype原型
既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...
最新文章
- 如何让机器获得幽默感——Goolge图学习技术揭秘
- HDU 4391 Paint The Wall 段树(水
- oracle 内存结构 share pool sql解析的过程
- 任正非谈鸿蒙系统失误,谷歌也没想到会来的这么快,任正非谈鸿蒙:系统不难,生态快完善...
- RabbitMQ的元数据重建
- 怎么去掉Flex4生成的SWF加载时的进度条
- java接口文档生成工具_【分享】接口文档生成工具apipost
- Java中的HashCode(1)之hash算法基本原理
- 开课吧:怎样才能做软件架构师?
- WAP 1.X, WAP 2.0
- Matlab plot3显示成平面图像
- 庞果答题:亿阳信通:不可表示的数 的一个人见解(8-13第二次更新。)
- 微信小程序-tab标签栏实现教程
- Latex 定制合并表格
- 关系模式(关系模式必须遵循)
- 2012考研计划时间安排表
- flowable报错FlowableTaskAlreadyClaimedException问题
- 影响人类!写入历史!疫情年最值得铭记的6个大事件
- 小米2s刷原生安卓_小米2/2S刷原生安卓Android4.4ROM刷機教程
- C语言:简单的利润与奖金
热门文章
- 产品经理之深度学习促进产品之分类(三)
- 华中科技计算机基础第五次,华中科技大学c++第5次上机作业
- python编程设计_程序设计入门—Python
- 【Flink】flink-1.12 通过 -t 指定模式后无法指定yarn参数
- 【java】深入理解Java JVM虚拟机中init和clinit的区别
- 【Elasticsearch】ES Elasticsearch查询优化
- 【Linux】Linux查看机器负载-CPU负载 CPU使用率达到100%
- 【Kafka】Failed to send data to Kafka: Failed to update metadata after 60000 ms
- 【JVM】JVM-codecache内存区域介绍
- Netty : netty 3如何解决空轮询bug