这是关于原型链的一系列的现象与原理的解释以及例子 【转载请注明出处与地址】 分成4个部分阐述: 1.如何创建一个对象 2.使用原型链prototype实现对象的继承. 3.原型链上属性和方法的联系与规则 4.深入剖析原型链。 一、如何创建一个对象: 1.使用关键字new创建。 var obj=new Object; 或者 function c() {} var obj=new c(); 2.使用花括号创建。 var obj={}; 我们知道,function是定义一个函数,里面的var 都是局部变量,那么如何声明一个对象的属性和方法呢。秘密就在于this关键字。在函数内部使用this关键字,就相当于是对象的属性和方法的声明这个变量是存在的。具体的例子如下: function a() { this.a=1; this.get=function() { return this.a; } } 那么只要使用用var obj =new a();即创建一个对象的实例,里面就包括function里面的this属性和方法的就会直接拷贝到对象变量obj上。直接使用a.a的方法即可调用相应的属性和方法。 但是注意,除非实例化function a(),否则无法调用里面的this关键字指向的属性以及方法。 因为此时this上定义的属性以及方法类似于C++/JAVA等面向对象声明的属性以及方法。因此,这种定义函数的方法也被称为JS的构造函数。 二、使用原型链prototype实现对象的继承. 所有函数function都有一个默认的属性prototype,通过用typeof函数测试我们可以看到prototype是一个对象。 alert(typeof(a.prototype)); 结果: 那么这个prototype的属性到底有什么用呢~? 既然是一个对象那么赋值的时候就当然是付给prototype一个实例了。事实上,只要把一个实例赋给prototype这个属性,那么这个function就具有这个实例的属性和方法。相当于我们常说的继承。请看下面的代码: function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b构造函数 { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//继承实例。 var obj =new b();//实例化函数b alert(obj.get()); 就是这么简单的逻辑,我们就是使用对象b实例化的obj,输出继承了父类a的方法get。输出父类a里面的属性ia。大家可以看到,这样就轻松地实现了继承。 那如果a又继承另外一个对象x怎么办? 答案当然是b会继承a所继承的所有东西。而他们的关系就像用prototype属性连起来一样。所以我们可以看成也是一个由prototype连接而成的链表,人称原型链。 三、原型链上属性和方法的联系与规则 首先我们明确一个概念,原型链就是一串好像用属性prototype连接而成的,每个节点具有属性和方法甚至函数过程的链。这种链式结构我们无疑可以发现一个很重要的问题----链上的节点之间发生属性或者方法重名怎么办?下面我们从读和写两方面来解析这条原型链的属性和方法的使用过程。 读: 从上面的例子里,alert(obj.get())输出的结果是什么呢,如果运行过一次,我们可以发现输出的结果是1. 但是我们可以看到,构造函数b定义的时候是没有get的方法的,同时,get方法调用的属性ia也是b中不存在的,那么我们在拥有prototype继承的构造函数所实例化的对象是如何调用属性和方法的呢。 结论是:对于调用实例化某一构造函数的对象的方法或者属性的时候,js会在原型链最结尾的点,也就是C++/JAVA上所描述的子类,上述例子中的b函数上,查找是否有所需要的方法或者属性,如果找不到的话,就会根据赋值给prototype的父节点对象,父构造函数上查找对应的属性和方法,就这样按照这种规则查找出对应名称的属性或方法。如果链上节点都不存在的话,当然就会输出undefined。 如果子节点有该属性或者方法,同时父节点也有的时候,当然会优先考虑子节点的,这也类似于C++/JAVA上所描述的覆盖的概念,子类的属性或者方法覆盖父类的。 而在上述例子中,get方法调用了一个this.ia,那么查找此此元素的时候,也会遵循上诉的原则,先查找构造函数b上是否有属性ia,没有的话再查找a上的构造函数上的属性ia。最后输出结果1。如果我们在构造函数b上添加一个属性this.ia=2,那么结果会如上述结论所说输出2. 写: 我们都知道,new操作会建立一个和构造函数一模一样的副本,开辟一个空间存放对象。但是我们从上面的操作可以看到,对于函数链上的属性,都可以被各个实例所访问,那么,js在实例化有prototype继承的构造函数的时候,是把链上的节点都实例化一次,还是被所有实例所共享呢?下面我们看下面例子。 function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b构造函数 { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//继承实例。 var obj1 =new b();//实例化函数b var obj2 =new b();//实例化函数b alert(obj1.ia);//输出1,因为他是父类a中的ia alert(obj2.ia);//输出1,因为他是父类a中的ia obj1.ia=2; alert(obj1.ia);//输出2,因为写操作会在实例对象建立一个副本ia并且赋值2,无修改其原型链上的父节点。 alert(obj2.ia);//输出还是1,因为他是父类a中的ia b.prototype.ia=3;//修改原型链上的属性ia。 alert(obj1.ia);//输出2,因为已经在实例上建立了副本,所以优先读取副本。 alert(obj2.ia);//输出3,因为子类b中不存在,所以还是查找父节点(prototype对象上的对象)上的ia,由于父节点上的ia已经被修改成3,所以输出3. 上面的例子说明了2件事: 1.写操作并不是直接查找原型链上的属性,然后更改他,而是直接在实例上创建在一个同名对象。由于实例上已经存在这个属性,所以下次读取的时候优先读取这个已存在的,相当于原型链上的原属性被覆盖(但是还是存在的)。 2.Prototype链上的节点(父类)都是被子类实例化后的对象所共享,也就是只有唯一的一个对象prototype,因此当我们修改b.prototype.ia=3;/后,obj2输出的也是3,说明他是被其他没有创建ia属性副本的实例所共享的。 这样我们就清晰了,原型链只有一条,并且不会因为子类实例化和把链上的节点,属性与方法都实例化,他将被所有子类的实例化对象所共享。 而这个原型链上的父类是准读不准写(通过子类实例化对象改变链上节点的属性与方法)。一旦你的实例化对象进行和父类属性与方法同名的写操作时,就会在实例化对象上建立对应的副本,同时进行写操作,此时这个实例也覆盖了原型链上的这个属性和方法。这种方法很好的保护了原型链上节点的共享性,不用担心不小心被其他实例所修改。这样大大地节省了内存,可以在频繁的对象创建中,有效地减少了内存空间的使用。 当然可以通过函数b上的prototype对象来修改链上的属性与方法,这样就可以做到一改全改,让子类共享的属性发生改变。如上面的 b.prototype.ia=3;操作。 这种做法也衍生出一种叫做延时绑定的思想,在使用的时侯才进行属性和方法的绑定,这种行为是可以通过原型链、prototype这个属性实现的。这样可以很方便地应用到你的编程中,但是注意,这种方法还是弊大于利的,因为可以在任何地方进行重绑定。所以程序者也许不知道在何时进行了绑定,使得代码很混乱,同时在大代码量的情况下,照成不可预料的结果。因此,延时绑定必须慎用。 四、深入剖析原型链。 上面说到,原型链是由prototype连在一起的,事实上这种说法是不严谨,甚至可以说是错误的,因为prototype是一个对象,并且实例是没有prototype这个属性的,但是,有比prototype更好的,用来表现原型链的东西,这是对象实例后的一个私有属性,ie下是不可访问的,但是用firefox是可以查看的,它才是真正的作为实例在原型链上查找属性与方法的一个类似指针的属性。可以这么说,prototype是函数所有的,而__proto__是实例化的对象存在的属性。我们常把这个__proto__指向的原型成为父原型。因为prototype是一个对象的实例,所以原型也有父原型。下面给出一段例子来解释这个现象。 function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b构造函数 { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//继承实例。 alert(a instanceof Function);//a是Function的实例; alert(a.__proto__ === Function.prototype);//a的父原型指向到Function的原型; alert(b.__proto__ === Function.prototype);//a的父原型指向到Function的原型 var obj =new b();//实例化函数b alert(typeof(obj.__proto__));//输出obejct,说明是一个对象 alert(obj instanceof Object);//ture.obj是其中一个对象 alert(obj.__proto__===b.prototype);//ture。因为__prototype指向父原型 alert(obj.__proto__.__proto__===a.prototype);//ture。因为__prototype指向父原型 alert(obj.__proto__.__proto__.__proto__===Object.prototype);//ture。因为__prototype指向父原型 alert(Object.prototype.__proto__);//null。因为Object的原型是所有父原型的顶端,它不再具有父原型; alert(Function instanceof Object);//Function是Object的实例; alert(Function.__proto__ === Function.prototype);//Function的父原型指向到Function的原型; alert(Function.prototype.__proto__ === Object.prototype);//Function的原型的父原型指向到Object的原型 alert(Object.__proto__ === Function.prototype);//Object的父原型指向到Function的原型; 从上面的例子我们再也清晰不过了,实例查找原型链的时候使用的__proto__ 这个私有属性,通过这个属性一层一层地遍历原型链,而原型链的最终父原型是Object.prototype,它是所有实例的父原型,只要修改这个父原型,那么所有的实例都将用到修改的属性。 同时。Function.prototype是所有函数的父原型,而它Function.prototype的父原型也是Object.prototype。到了这里,我们可以清晰地看到一个实例后面的原型链的全貌了。

转载于:https://www.cnblogs.com/si-ren/archive/2010/12/29/2447674.html

Javascript原型链相关推荐

  1. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = {d: 40};var a = {x: 10,calculate: function (z) {retu ...

  2. 深度解析JavaScript原型链

    深度解析JavaScript原型链 文章目录 深度解析JavaScript原型链 前言 JavaScript原型链,这里只分享我自己的见解 一.原型链是什么 二.心得 三图解 总结 前言 JavaSc ...

  3. JavaScript原型链污染攻击

    前言 最近在看js的时候看到p神的一篇关于js原型链污染的文章,学习一下. 下面转自p神:深入理解 JavaScript Prototype 污染攻击 还有一篇案例关于js原型链污染的ctf题:从一道 ...

  4. JavaScript 原型链和继承面试题

    JavaScript 原型链和继承问题 JavaScript 中没有类的概念的,主要通过原型链来实现继承.通常情况下,继承意味着复制操作,然而 JavaScript默认并不会复制对象的属性,相反,Ja ...

  5. JavaScript 原型链常用方法

    JavaScript 原型链常用方法 对象属性类型 数据属性 Configurable(表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性) En ...

  6. 技术分享经典 javaScript原型链面试题

    技术分享 javaScript原型链 一个小题目 前置知识 变量提升和函数提升 this指针的指向 原型链是什么 new操作符的工资流程 一个小题目 今天我们部门的技术分享上出现了这样一段代码: fu ...

  7. 如何理解JavaScript原型链

    如何理解JavaScript原型链 实例对象与原型对象的关系 构造函数.原型对象和实例对象之间的关系 原型链结构图 函数在原型链中的结构 原型链的理解和总结 实例对象与原型对象的关系 构造函数.原型对 ...

  8. JavaScript原型链以及Object,Function之间的关系

    JavaScript里任何东西都是对象,任何一个对象内部都有另一个对象叫__proto__,即原型,它可以包含任何东西让对象继承.当然__proto__本身也是一个对象,它自己也有自己的__proto ...

  9. 理解JavaScript原型链

    JavaScript中的每个对象都有一个prototype属性,我们称之为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联起来了一条原型链,原型链的链头是object,它的prototy ...

  10. JavaScript原型链的理解

    一.原型链的概念 JavaScript是一门面向对象的编程语言,JavaScript 中的所有事物都是对象,并且对象与对象之间不是彼此独立的,而是有"继承"关系的. 这种" ...

最新文章

  1. springmvc国际化 基于浏览器语言的国际化配置
  2. C语言 NULL与0 对应的地址
  3. 11、MySQL算术运算符
  4. 思维导图_教学工具思维导图
  5. CNN更新换代!性能提升算力减半,还即插即用
  6. 解决自定义UITableViewCell在浏览中出现数据行重复的问题
  7. 软件测试---正交试验法
  8. kinect 2.0 SDK-深度图与彩色图对齐
  9. 阿里巴巴重要开源项目汇总(资料参考)
  10. 如何打造数字原生企业?易捷行云EasyStack有话要说
  11. 带宽、线速、吞吐量概念
  12. 理解计算:从根号2到AlphaGo 第3季 神经网络的数学模型
  13. 设计模式学习难度系数排名
  14. 视觉工程师面试50问
  15. 【springboot】.isEmpty()和ObjectUtils.isEmpty()的使用注意点
  16. 剖析Android开发未来的出路在哪里,这原因我服了
  17. 查缺补漏:集和与非平凡属性
  18. stream之List转Map---Collectors.toMap()介绍
  19. 绕过卡巴斯基主动防御系统方法的讨论
  20. 客服端向服务端发布、订阅、取消

热门文章

  1. python画指数函数图像_python实现画出e指数函数的图像
  2. 如何删除linux的root权限,永久删除现代Linux的root权限
  3. python怎样判断一个文件是否存在_python如何判断一个文件是否存在
  4. PyTorch框架:(5)使用PyTorch框架构建卷积神经网络
  5. 数字图像处理:图像就是函数的解读
  6. 三维点云课程第一章:应用
  7. LabVIEW仪表盘识别(实战篇—6)
  8. 图像金字塔与resize函数
  9. python数据分析面试_python数据分析面试
  10. CamVox:一种低成本、高精度的激光雷达辅助视觉SLAM系统