一.两个原型
很多人都知道javascript是原型继承,每个构造函数都有一个prototype成员,通过它就可以把javascript的继承演义的美轮美奂了.
其实啊,光靠这一个属性是无法完成javascript的继承.
我们在代码中使用的prototype完成继承在这里就不多说了.大家可以查一下资料.
另外一个看不见的prototype成员.
每一个实例都有有一条指向原型的prototype属性,这个属性是无法被访问到的,当然也就无法被修改了,因为这是维护javascript继承的基础.

  //构造器声明
function Guoyansi(){ }
function GuoyansiEx(){}
//原型继承
GuoyansiEx.prototype=new Guoyansi();
//创建对象
var g1=new GuoyansiEx();
var g2=new GuoyansiEx();

上面的代码中的对象可以用下面的图来说明

二.原型的维护
一个构造器产生的实例,其constructor属性总是指向该构造器.我们暂且认为该话是对的.

 function Guoyansi(){ }
var obj1=new Guoyansi();
console.log(obj1.constructor===Guoyansi);//true

其实构造器本身是没有constructor这个属性的,那么这个属性是来自哪呢?
答案是:来自原型.
因此得出下面的结论

 obj1.constructor===Guoyansi.prototype.constructor===Guoyansi

既然我们可以通过constructor来寻找构造器.因此我们就可以进一步完善上面的图了.

 function GuoyansiEx(){}
GuoyansiEx.prototype=new Guoyansi();
console.log(GuoyansiEx.constructor===GuoyansiEx)//false

根据上图,上面的结果应该是true,但为什么是false呢?
现在做个分析.
GuoyansiEx的原型被Guoyansi的实例重写了,那么GuoyansiEx的原型中的constructor自然也是来自Guoyansi的实例.
而Guoyansi实例中的constructor又是来自Guoyansi.prototype.而Guoyansi.prototype没有被重写,
所以Guoyansi.prototype的constructor指向Guoyansi(构造函数);
根据以上分析得出下面的结论

GuoyansiEx.constructor===Guoyansi.constructor===Guoyansi;

如果在开发过程中对于Constructor的指向要求非常精确的话,可以做如下处理.

/**方法一:**/
1 function Guoyansi(){}
function GuoyansiEx(){}
GuoyansiEx.prototype=new Guoyansi();
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
  /**
方法二
**/
function Guoyansi(){}
function GuoyansiEx(){
this.constructor=arguments.callee;
}
GuoyansiEx.prototype=new Guoyansi();
  /**
方法三
**/
function Guoyansi(){}
function GuoyansiEx(){
this.constructor=GuoyansiEx;
}
GuoyansiEx.prototype=new Guoyansi();

三.看不见的原型有什么用呢?
看得见的原型链我们可以对他操作来完成我们的继承,那么这个看不见的原型链我们既看不见,又无法操作.要它有何用.
面向对象中继承有一个特性:相似性.子类与父类具有相似性.因此在子类中你是无法用delete删除从父类继承而来的成员.也就是说子类必须具有父类的特性.
为了维护这个特性,javascript在对象的内部产生了一条我们看不见的原型属性,并且不允许用户访问.这样,用户可以处于任何目的来修改constructor,
而不会破坏子类拥有父类的特性.
简而言之:内部原型是javascript的原型继承机制所需要的,而外部原型是用户实现继承所需要的.

四.火狐引擎SpiderMonkey中的__proto__
还是这段代码.

  function Guoyansi(){}
Guoyansi.prototype.age=24;
function GuoyansiEx(){}
var obj1=new Guoyansi();
GuoyansiEx.prototype=obj1;
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
var obj2=new GuoyansiEx();

我现在想要从obj开始向上访问父类Guoyansi的prototype的属性的age.
思路是这样的.
第一步:obj2====>obj2.constructor.prototype
第二部:obj2.constructor.prototype===>GuoyansiEx.prototype;
第三部:GuoyansiEx.prototype===>obj1;
第四部:obj1.constructor====>Guoyansi
第五部:Guoyansi.prototype.age

写成这这样:console.log(obj2.constructor.prototype.constructor.prototype.age)//24;
最终的结果是24.
最终的结果是24.可以正常执行,但是在好多书上说constructor修改后,级无法在找到父类中的原型了.不知道是怎么回事.

在火狐中提够了一种更加简洁的属性._proto_
SpiderMonkey中默认在任何创建的对象上添加了一个名为_proto_的属性,该属性指向构造器所用的原型.
其实就是我们上面提到的不可见的原型链,只不过是在这个地方变相的公开而已.
可以这样访问到age
console.log(obj2.__proto__.__proto__.age);//24
这样的确是成功的访问到了父类的原型属性,但是这个属性只适用于火狐,在其他浏览器中是会出错的.
在E5中对Object做出了扩展Object.getPrototypeOf(),可以访问到所有父类的原型了.

 function Guoyansi(){}
Guoyansi.prototype.age=24;
function GuoyansiEx(){}
var obj1=new Guoyansi();
GuoyansiEx.prototype=obj1;
GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
var obj2=new GuoyansiEx();
var proto=Object.getPrototypeOf(obj2);
while(proto){
console.log(proto.constructor);
proto=Object.getPrototypeOf(proto);
}
console.log("object的原型"+proto);

结果是:GuoyansiEx
Guoyansi
Object
object的原型null

个人觉得这些应该算是javascript面向对象的精髓之一了.

javascript精髓篇之原型链维护和继承.的更多相关文章

  1. javascript 重难点(原型链 this) 理解总有一个过程,不要急,循序渐进!

    开始补充: 1. 将函数定义作为对象的属性,称之为对象方法.2. this的指向是由它所在函数调用的上下文决定的(语境),而不是由它所在函数定义的上下文决定的.3. 因为当一个函数作为函数而不是方法来 ...

  2. javascript 创建对象及对象原型链属性介绍

    我们知道javascript里定义一个普通对象的方法,如: let obj = {}; obj.num = 1; obj.string = 'string'; obj.func = function( ...

  3. JavaScript高级内容:原型链、继承、执行上下文、作用域链、闭包

    了解这些问题,我先一步步来看,先从基础说起,然后引出这些概念. 本文只用实例验证结果,并做简要说明,给大家增加些印象,因为单独一项拿出来都需要大篇幅讲解. 1.值类型 & 引用类型 funct ...

  4. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

  5. javascript 面向对象 new 关键字 原型链 构造函数

    JavaScript面向对象JavaScript 语言使用构造函数(constructor)作为对象的模板.所谓"构造函数",就是专门用来生成实例对象的函数.它就是对象的模板,描述 ...

  6. JavaScript 随笔2 面向对象 原型链 继承

    第六章 面向对象的程序设计 1.创建对象的几种方式 A)工厂模式 function CreatObj(name,sex,age){ this.name=name; this.sex=sex; this ...

  7. javascript基础学习系列-原型链模式

    1.demo代码如下: 2.画图如下: 3.规则: 1)每一个函数数据类型(普通函数/类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值 2)并且prototy ...

  8. javaScript之深度理解原型链

    经过多次的翻阅书籍终于对原型链在实际代码中的应用有了新的认识,但是不知道是否有错误的地方,还请大神多多指教. 构造函数.原型和实例的关系:每个构造函数都有一个原型对象funName.prototype ...

  9. 在学习java之余,js的使用精髓-闭包和原型链

    这里分享下廖雪峰官网写的js教程,内容写的比较实用,易懂,其中简介的原型链和闭包的知识,小伙伴们一起上呀,畅游在知识的海洋中: 地址:https://www.liaoxuefeng.com/wiki/ ...

随机推荐

  1. 使用向量化的 if:ifelse

    进行分支计算的一个替代方法是 ifelse( ).这个函数接收一个逻辑向量作为判定条件,并且返回一个向量.对于逻辑判定条件内的每一个元素,若是 TRUE,则选择第 2个参数 yes 中所对应的元素:若 ...

  2. Java IO流-标准输入输出流

    2017-11-05 19:13:21 标准输入输出流:System类中的两个成员变量. 标准输入流(public static final InputStream in):“标准”输入流.此流已打开 ...

  3. 智课雅思词汇---二十七、形容词后缀-ant/-ent

    智课雅思词汇---二十七.形容词后缀-ant/-ent 一.总结 一句话总结: ...的 后缀:-ant ①[形容词后缀] 大部分与-ance或-ancy,相对应,表示属于...的.具有...性质的 ...

  4. 使用Spring Loader或者Jrebel实现java 热部署

    .其实JRebel和Spring-Loaded就是一个开发环境下的利器,skip build and redeploy process,大大提升了工作效率!而非生产环境的利器...因为线上reload ...

  5. 使用PMD进行代码审查(转)

    原文地址:使用PMD进行代码审查 很久没写博客了,自从上次写的设计模式的博客被不知名的鹳狸猿下架了一次之后兴趣大减,那时候就没什么兴致写博客了,但是这段时间还没有停下来,最近也在研究一些其他的东西,目 ...

  6. redis.conf配置文件参数说明

    参数说明 redis.conf 配置项说明如下: 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程     daemonize no 2. 当Redis以守护 ...

  7. Python数据类型-03.序列-列表和元组

    本文主要记录关于Python序列中列表和元组的定义特点和常用方法 1.序列(sequence) 1.1.序列的定义 序列是一组有顺序的元素的集合(其实是是对象的集合,后期会引入“对象”这个概念)序列包 ...

  8. mt7601u: probe of xxxx failed with error -2

    /************************************************************************ * mt7601u: probe of xxxx f ...

  9. 高性能Mysql学习笔记之事务

    传送门 什么是事务? 事务就是一组原子性的SQL查询,或者说一个独立的工作单元.如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就会执行该组查询.如果其中有任何一条语句因为崩溃或其他原因无 ...

  10. endnote x7 破解版 关联word2010/2013

    方法/步骤   1 首先在已安装EndnoteX7的条件下,打开word2013在工具栏上方未见“EndnoteX7”标识,则需要将两者关联. 2 打开word左上角的“文件”,然后点开“选项” 3 ...