图解JS原型和原型链实现原理_javascript技巧

来源:脚本之家  责任编辑:小易  

先来看一下原型2113JavaScript的所有function类型的对5261象都有一个prototype属性,这个prototype属性本身是一4102个object类型的对象,因此1653我们也可以给这个prototype对象添加任意的属性和方法。先看以下代码<script type=”text/javascript”> Person = function(){ this.name = “jack”; }; Person.prototype.name = “rose”; p = new Person(); alert(p.name);//输出jack delete p.name; alert(p.name);//输出rose </script> 由此可见当我们调用p.name时首先到p对象内部去查找name属性如果没有就去p对象的原型(prototype)中去查找name属性再来看以下代码<script type=”text/javascript”> Person = function(){ this.name = "jack"; }; Employee = function(){ this.name = "emp"; }; 1 Employee.prototype = new Person(); 2 Employee.prototype.name = "protoName"; Person.prototype.name = "rose"; e = new Employee(); alert(e.name);//输出emp delete e.name; alert(e.name);//输出protoName delete Employee.prototype.name; alert(e.name);//输出rose</script> 上面这段代码可以看出调用e.name 首先到e对象内部查找可以找到emp,删除后然后到e对象的原型中(prototype)去查找name属性此时找到protoName再删除,此时发现程序执行的流程是到Person的原型中去找出了rose, 由此可见代码行1中Employee的原型关联到了Person,相当于Person是Employee的父类。读者可能会发现上面这段描述写的很敷衍为什么顺序不是这样e对象内部->e对象原型->person对象内部->person对象原型而是e对象内部->e对象原型-> person对象原型其实关键就在于1、2两行代码做个实验调换1、2两行代码的位置即2 Employee.prototype.name = "protoName";1 Employee.prototype = new Person(); 再运行看看结果alert(e.name);//输出emp delete e.name; alert(e.name);//输出jack delete Employee.prototype.name; alert(e.name);//输出rose</script> 这种输出结果就好像如下顺序e对象内部-> person对象内部->person对象原型如果你是真心想学习JS、以后想朝着这个方向发展,那么你一定要来这个企鹅裙,前面前面是2九六,中间是五九一,最后面就是2九零,连起来就是完整的了,来这里可以这里学习经验,得到专人解答,这样你可以成长的更快!!!为什么有这样的区别,关键就是这句话Employee.prototype = new Person(); Employee的原型对象被赋值成了一个Person对象即Employee的原型被修改了,那么写在这句前面的Employee.prototype.name ="protoName";就没有用了和删除这句话效果一样那么Employee.prototype.name也就理所应当等于person对象的name 给Employee.prototype.name赋值也就相当于给person对象的name属性赋值那么原来的jack就被覆盖了原型链就是prototype对象的一条关系链这条链的末端就是Object对象的原型当调用对象的属性或方法时首先会去对象内部查找,然后再依次顺着原型链条一直找到Object,书上是这么说的www.zgxue.com防采集请勿采集本网。

在我初学 JS 语言的继承机制原型和原型链的时候,我一直理解不了这种设计机制,再加上之前原有对 Java继承的理解,在学习 JS 继承机制的设计上踩了一个大坑,很多知识点前期都是死记硬背,无法真正的理解它的设计思想。

每个 JavaScript 对象内部都有一个指向其它对象的“指针”或者 “引用“, 并通过这种方式在对象之间建立了一种联系,形成了一种链式结构,我的理解这就是

JS 中的继承机制思想可以说是学习 JS 的一个核心思想,更可以说是 JS 中的一个命脉,往往这些复杂、抽象的继承关系,以及专业术语、代名词确成为了困扰初学者的绊脚石。当我真正理解它的设计思想时,其实并没有那么复杂,而且觉得非常简单。

在刚刚接触JS原型链的时候都会接触到一个熟悉的名词:prototype;如果你曾经深入过prototype,你会接触到另一个名词:__proto__(注意:两边各有两条下划线,不

在写这篇 JS 的原型和原型链的文章之前,我在谷歌搜索检索了大量的高赞有关 JS 原型和原型链的文章,大部分都是围绕着“是什么”来讲的,导致部分初学者缺少对 JS 继承的设计与实现的前后关联性,还是很难准确的去理解。

个人感觉,没什么联系。 一般来说,作用域链是针对变量的,js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域,如果函数1里面又定义了函数2(一般都是匿名函数), 那么就有了这么一个作用域链全局作用域==>函数1作用域==>函数

我们先要明白,学习这块内容知识要知道设计者“ 为什么这样做 ” 远比 “怎么做的” 重要的多这才是掌握这部分内容的关键。

javascript原型,原型链特点:原型链实现了继承。 JS中每个函数都存在有一个原型对象属性prototype。并且所有函数的默认原型都是Object的实例。每个继承父函数的

今天小鹿对 JS 的继承机制要做一个系统的总结,从设计者的角度出发,将复杂的设计思想用动画呈现,将零碎的知识点体系化,争取让你一文搞懂 JS 的继承机制思想(原型和原型链)。

function f1(){}; var f2 = function(){}; var f3 = new Function('str','console.log(str)'); var o3 = new f1(); var o1 = {};

思维导图

1.JS 的发展史

要想贯彻 JS 的核心设计思想,我们要从 JS 的诞生说起。

1.1 为什么会诞生 JavaScript ?

相对比较成熟的浏览器是由网景公司发布的,早些年间,浏览器只能浏览网页内容,而不能进行用户交互。比如我们登录输入用户名和密码,在浏览器是不能进行判断用户是否真正输入了,而是通过服务器来判断,如果没有输入,返回错误提示用户,这种设计非常的浪费时间和服务器资源。

为了解决这个问题,网景公司需要开发一种运行在浏览器中的脚本语言,用来简单的做用户输入校验等操作。

当时最流行的语言是面向对象的Java编程语言 ,网景公司为了能够借助 Java将浏览器脚本语言流传开,所以起名 JavaScript。其实两者没有任何的关系。

1.2 存在的问题

JS 中的数据类型设计受当时 Java流行的影响,都是对象类型,这时候就遇到问题了,有对象必然涉及到继承机制,那么 JS 的继承机制要设计成 Java一样呢?还是另有设计思想?

2.JS 继承的设计思想

JS 的开发者想如果设计成像 Java一样有“类”的概念岂不是和 Java一样成为了一种完全面向对象的编程语言了?最后决定自己设计一种继承机制,但是它的设计思想还是采用了 Java的一些特性。

2.1 生成对象

通常 Java 生成对象是通过 new 的方式,通过类生成一个实例对象的过程。但是 JS 中并没有类,那 JS 的设计者要怎么做?

他找到了 Java 和 JS 的共同点就是两者都有构造函数, Java的 new 的过程内部其实调用了构造函数。但是 JS 是没有“类”的概念的,于是 JS 就把new 一个“类”设计成了 new 一个构造函数,于是构造函数成为了一个实例对象的原型对象。

3.为什么要设计原型对象?

上述这样的原型设计有一个致命的缺点就是无法共享公共属性。

因为我们知道,每 new 一个对象,生成的实例是两个不同的对象。所以共有的属性也不是共享的。

所以要设计一个对象专门用来存储对象共享的属性,那么我们叫它「原型对象」。

4.什么是原型对象?

要想让构造函数生成的所有实例对象都能够共享属性,那么我们就给构造函数加一个属性叫做prototype,用来指向原型对象,我们把所有实例对象共享的属性和方法都放在这个构造函数的prototype属性指向的原型对象中,不需要共享的属性和方法放在构造函数中。

这里有一点疑惑就是,我们知道对象可以设置属性,函数也可以设置属性吗?对于初学者来说是比较懵逼的,那我们可以稍微的简单说一下:

JavaScript 中的函数拥有对象的所有能力,也因此可被称作为任意其他类型对象来对待。当我们说函数是第一类对象的时候,就是说函数也能够对象的一些功能,比如添加属性,函数当做参数传递等。

所以说,实例对象一旦通过构造函数创建,就会自动给实例对象赋值上原型对象上共享的属性或方法。说清楚一点就是该对象属性都指向了原型对象的属性值。

5.对象和函数在原型链关系?

上述的图反映了对象以及函数在原型链中的关系,如果你觉的上边的这张图看懵逼了,没关系,我刚开始学习原型链的时候,根本不知道上边这是什么“清明上河图”,小鹿下面通过一步步的拆分讲解,看这张图就非常简单,没错,非常简单。

我们文章的开头也说了什么是原型对象,说白了就是构造函数的一个 prototype属性,这个属性就指向原型对象。

其实我们其中一些连接属性没有讲到,只讲到了prototype属性,下面一张图来将剩下的属性补充完整,我们只要把这张图印到大脑中就可以了。

我们来分析一下上图,首先我们先要声明一个狗的构造函数,定义其名字和体重属性(私有属性),同时每个构造函数我们上边讲到了,都会有一个prototype属性。

这个prototype指向的就是原型对象,原型对象放的就是对象共享的属性。但是注意,原型对象里有一个constructor属性,这个属性又指回了构造函数。

我们通过 new 构造函数生成两个狗的对象实例,一个叫豆豆,一个叫贝贝,这两个是两个不同的对象,名字体重都不相同,但是他们会共享原型对象上的属性 type,它们共有的属性都是犬类。

在 JS 所有对象中,只要是对象,都会有一个内置属性叫做_proto_,而且这个属性是系统自动生成的,只要你创建一个对象,这个对象就有这个属性。这个_proto_属性指向的是原型对象。

通过上边的分布讲解,我们明白了构造函数与对象实例以及原型对象的关系。

总结为一句话为:

构造函数的 prototype 指向原型对象,原型对象有一个 constructor 属性指回构造函数,每个构造函数生成的实例对象都有一个 _proto_ 属性,这个属性指向原型对象。

没错,原型就是这么简单。但是你会发现,原型也是对象呀,你说只要是对象都会有一个_proto_属性指向自身构造函数的原型对象。

没错,要想知道原型对象的_proto_属性指向谁,就要知道是哪个构造函数创建了原型对象?

我们知道,所有的 JS 对象的都是继承了一个叫做 Object 的对象。可以理解为Object 构造函数创造了这个万物,他们的关系如下,和上边是同样的道理,上边总结的那句话好好理解一下。

但是上图中会有一个疑问,Object 构造函数原型对象的也是对象,它肯定也有一个_proto_属性,为什么会指向 null 呢?

我们在拿上述总结的那句话,_proto_属性指向的是自身构造函数的原型对象,自身的构造函数是谁?是 Object 构造函数,那 Object构造函数的原型是谁?当然是本身(如图),所以把_proto_指向了null。

上边的关系如果不仔细整理的话确实很乱,尤其是对于初学者,但是如果像小鹿这样已整理,再乱的关系把它安排的井井有条,没有理解,就多看几篇文章。

6.原型链

我们还有一个问题没有解决就是原型链?既然我么你知道什么是原型了,原型链是什么?顾名思义,肯定是一条链,既然每个对象都有一个_proto_属性指向原型对象,那么原型对象也有_proto_指向原型对象的原型对象,直到指向上图中的null,这才到达原型链的顶端。

不要忘了,上边那种图我们还没有把它理解,我们把图自上而下理解。

第一张图分解,上边小鹿画的图的关系和这个一样的,仔细对比一下,很简单,第一张图就这么解决了。

我们继续向下分割,看第二张图。

第二张图怎么还是那么眼熟呢,这不是小鹿上边分析的 Object 的关系图吗?对的,没错。

第三张图,稍微绕个弯子,但是换汤不换药呀,听小鹿分析来。

看着还是眼熟,只不过把function换成了Function,f 变成了大写的 F,这里涉及到一个知识点就是,在 JS 中,所有的 function函数都是由Function继承来的,可以说是Function是所有 function的祖宗。

那Function是由谁生产来的?我们看到图中的Function函数有_proto_属性了,而且属性指向自己的原型对象,那不就是自己繁衍自己吗?可以这么理解。

小结

这里我们在纵观全图,总结几条定义你比对着图去找。

1、所有的实例的_proto_都指向该构造函数的原型对象(prototype)。

2、所有的函数(包括构造函数)是Function的实例,所以所有函数的 _proto_的都指向Function的原型对象。

3、所有的原型对象(包括 Function的原型对象)都是Object的实例,所以_proto_都指向 Object(构造函数)的原型对象。而 Object构造函数的 _proto_指向 null。

4、Function构造函数本身就是 Function 的实例,所以_proto_指向Function的原型对象。

全篇文章的精华都在最后的总结部分,前边的所有分解讲解是为了让你理解这些函数对象以及原型对象之间的关系,这关系都是固定的,谁指向谁,都是写死额,只要你记住了他们的关系,这张图就理解的差不多了,能够理解完这张图,你的原型和原型链已经了解的很扎实了,但是还需要做一些面试题巩固一下。

学习了,还没2113用到过一个类要继5261承自一个类的这种情况,目前写4102的代码全部是1653简单的设置prototype属性。研究了一下你的这段代码(好像在哪见过类似的),核心部分还是简单的设置了一下prototype属性:extend(absObj, sprPropty);//clazz.prototype=superclass.prototypeextend(absObj, constructor(sprPropty));//clazz.prototype添加新属性了解了prototype机制,基本上也就理解了这段代码参考:www.w3school.com.cn/js/pro_js_inheritance_implementing.asp还有一个小问题,子类的initialize方法中估计都会调用superclass.initialize.call(this, options);,不然子类就不会有父类initialize中定义的属性了,这样完全可以写到clazz函数中:var clazz = function() {    //调用父类的构造方法,有点像java的构造方法中,super构造方法必须放到最前面   superclass&&superclass.prototype.superclass&&superclass.prototype.initialize.apply(this, arguments);   //调用子类的构造方法   this.initialize.apply(this, arguments);};/**还有一个**/ //如果无参数,直接返回类::::狗血,没参数clazz还能运行起来么,返回clazz有啥用if (arguments.length == 0) return clazz;//直接抛异常吧if (arguments.length == 0) throw new Error("狗血");追问能逐句逐个语法详细描述介绍一下吗? 我看了你的回复,大部分的思路都是对的,我也知道,我只是细节地方的技巧和深层原理和如何灵活拓展不是很有梳理.因为只说大意的话我也了解CC.create返回父类和return的新对象,initialize是回调的虚函数.prototype需能做到重写而不是单纯的指针地址指向,所以要用到extent方法. 另外谢谢你对initialize父类继承的思路.追答嗯 学习了,你要问什么?内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • 详解react-native全球化多语言切换工具库react-native-i18n
  • 编写高性能javascript代码的n条建议
  • 解决layui checkbox 提交多个值的问题
  • js控制表格实现一条光线流动分割行的方法
  • javascript+turn.js实现图书翻页效果实例代码
  • javascript获取网页表单action属性的方法
  • 微信小程序三级联动地址选择器的实例代码
  • js实现的简练高效拖拽功能示例
  • 浅谈javascript中this在事件中的应用
  • 基于js中this和event 的区别(详解)
  • 详解javascript 原型链继承,要很详细很详细解答!高...
  • 如何理解javascript原型链
  • 最详尽的 JS 原型与原型链终极详解,没有
  • 怎么理解javascript原型链
  • js中什么是原型对象和原型链
  • 深入分析JS原型链以及为什么不能在原型链上使
  • javascript作用域链与原型链有联系吗?请从原理上分...
  • javascript原型,原型链 有什么特点
  • js里面的继承怎么理解,原型链呢,,好难理解啊,
  • 谈谈对原型链的理解 JS原型链怎么理解
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全基础知识javascript类库表单特效广告代码网页特效黑客性质javascript技巧domnode.jsjs其它首页javascriptjs原形与原型链深入详解javascript进阶(四)原型与原型链用法实例分析javascript 原型与原型链的理解及应用实例分析js原型和原型链原理与用法实例详解js学习笔记之原型链和利用原型实现继承详解javascript中构造函数与原型链之间的关系详解深入浅析js原型链和vue构造函数javascript原型链与继承操作实例总结详解react-native全球化多语言切换工具库react-native-i18n编写高性能javascript代码的n条建议解决layui checkbox 提交多个值的问题js控制表格实现一条光线流动分割行的方法javascript+turn.js实现图书翻页效果实例代码javascript获取网页表单action属性的方法微信小程序三级联动地址选择器的实例代码js实现的简练高效拖拽功能示例浅谈javascript中this在事件中的应用基于js中this和event 的区别(详解)js刷新页面方法大全js中settimeout()的用法详解js截取字符串常用方法详细整理js页面跳转常用的几种方式js删除数组里的某个元素方法js打开新窗口的2种方式js数组与字符串的相互转换方法js设置cookie、读取cookie、删除js 将json字符串转换为json对象的js关闭当前页面(窗口)的几种方式javascript查看大图功能代码实现window.addeventlistener来解决让一个js事javascript实现防止网页被嵌入frame框架的微信小程序提取公用函数到util.js及使用方精通javascript的this关键字微信小程序自定义弹出层效果bootstrap 布局组件(全)如何基于原生javascript生成带图片的二维javascript设计模式之装饰者模式详解篇js下关于onmouseout、事件冒泡的问题经验
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved