zoukankan      html  css  js  c++  java
  • javascript精髓篇之原型链维护和继承.

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

    1  //构造器声明
    2         function Guoyansi(){ }
    3         function GuoyansiEx(){}
    4         //原型继承
    5          GuoyansiEx.prototype=new Guoyansi();
    6        //创建对象
    7        var g1=new GuoyansiEx();
    8        var g2=new GuoyansiEx();

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

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

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

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

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

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

    1 function GuoyansiEx(){}
    2             GuoyansiEx.prototype=new Guoyansi();
    3             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(){} 2 function GuoyansiEx(){} 3 GuoyansiEx.prototype=new Guoyansi(); 4 GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
    1  /**
    2             方法二
    3             **/
    4             function Guoyansi(){}
    5             function GuoyansiEx(){
    6                 this.constructor=arguments.callee;
    7             }
    8             GuoyansiEx.prototype=new Guoyansi();
    1  /**
    2             方法三
    3             **/
    4             function Guoyansi(){}
    5             function GuoyansiEx(){
    6                 this.constructor=GuoyansiEx;
    7             }
    8             GuoyansiEx.prototype=new Guoyansi();

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

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

    1  function Guoyansi(){}
    2             Guoyansi.prototype.age=24;
    3             function GuoyansiEx(){}
    4             var obj1=new Guoyansi();
    5             GuoyansiEx.prototype=obj1;
    6             GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
    7             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(),可以访问到所有父类的原型了.

     1 function Guoyansi(){}
     2             Guoyansi.prototype.age=24;
     3             function GuoyansiEx(){}
     4             var obj1=new Guoyansi();
     5             GuoyansiEx.prototype=obj1;
     6             GuoyansiEx.prototype.constructor=GuoyansiEx;//重置constructor指向.
     7             var obj2=new GuoyansiEx();
     8             var proto=Object.getPrototypeOf(obj2);
     9             while(proto){
    10                 console.log(proto.constructor);
    11                 proto=Object.getPrototypeOf(proto);
    12             }
    13             console.log("object的原型"+proto);

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

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

  • 相关阅读:
    算法:最小公倍数的求解方法
    使用C语言中qsort()函数对浮点型数组无法成功排序的问题
    用两个栈模拟实现一个队列
    单链表反向查找
    单链表逆序
    斐波那契(Fibonacci)数列的几种计算机解法
    最大子列和问题
    Visual Studio个人常用快捷键
    数字根(digital root)
    秦九韶算法(霍纳算法)求解多项式
  • 原文地址:https://www.cnblogs.com/guoyansi19900907/p/3736694.html
Copyright © 2011-2022 走看看