zoukankan      html  css  js  c++  java
  • 一个有关原型的问题牵扯出的问题

    最近推荐一个朋友学习js,今天他问了我一个问题,问题如下:

     1 function Box (){}
     2 Box.prototype = {
     3     name : 'Lee',
     4     age : 28,
     5     run : function (){
     6         return this.name+this.age+'运行中...';
     7     }
     8 };
     9 var box = new Box();
    10 Box.prototype = {
    11     age : 200
    12 };
    13 alert(box.age);

    这里alert出来的结果是多少呢?结果是28,他问我为什么是28,我运行代码之后发现是28,但是我也没有想明白为什么是。虽然一直使用js,但是每次遇到原型这个地方的问题的时候我还是会蒙,一直对这个理解的不是很透彻。刚好借着这个问题,我详细的看了下书和资料,算是弄明白了为什么。

    这里先引用一段JavaScript高级程序设计(第三版)中的一段话。

    无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性。这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。

    这里有点抽象,我借用书中一个图说明下:

    这里可以看出Box.prototype.constructor == Box;

    上面的问题在哪里呢?当Box.prototype = {};一个新的对象的时候,这段代码:

    1 function Box (){}
    2 Box.prototype = {
    3     name : 'Lee',
    4     age : 28,
    5     run : function (){
    6         return this.name+this.age+'运行中...';
    7     }
    8 };

    这段之后,这个Box.prototype.constructor == Box;就不成立了,

    其实上面说的这段没啥用,只是为了凑字数显得字多,而接下来的new这个操作才是真正的起了作用。这里要理解new这个操作到底做了什么,在理解之前,先插入一段书上的原话:

    创建了自定义的构造函数之后,其原型对象默认只会去的constructor属性,至于其他方法,则都是从Object继承而来的。当调用构造函数创建一个新实例后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第五版中管这个指针叫[[Prototype]]。虽然在脚本中没有标准的方式访问[[Prototype]]。但Firefox, Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

    几把越看越晕了,看代码就好了:

    1 var box = new Box();
    2 // function new () {
    3 //     var box = {};
    4 //     box.__proto__ = Box.prototype;
    5 //     Box.apply(box, arguments);
    6 //       return box;
    7 // }
    8 注释部分只是方便理解

    如果这样的话,上面的问题就一下子晴朗了,因为在new的时候指定了box内部__proto__的指向,这个指向就是Box.prototype的指向,

    为了方便理解我把代码修改成如下:

     1 function Box (){}
     2 
     3 console.log(Box.prototype.constructor == Box);    //true
     4 
     5 var obj1 = {
     6     name : 'Lee',
     7     age : 28,
     8     run : function (){
     9         return this.name+this.age+'运行中...';
    10     }
    11 };
    12 
    13 Box.prototype = obj1;
    14 
    15 var box = new Box();
    16 // function new () {
    17 //     var box = {};
    18 //     box.__proto__ = Box.prototype;
    19 //     Box.apply(box, arguments);
    20 //       return box;
    21 // }
    22 
    23 console.log(box.age);
    24 
    25 
    26 var obj2 = {
    27     age : 200
    28 };
    29 
    30 Box.prototype = obj2;
    31 
    32 console.log(Box.prototype.isPrototypeOf(box));               //false
    33 console.log(Object.getPrototypeOf(box) == Box.prototype);    //false
    34 console.log(Object.getPrototypeOf(box) == obj1);             //true
    35 console.log(Object.getPrototypeOf(box) == obj2);             //false
    36 
    37 console.log(box.age);

    因为已经new过了,而new过之后修改Box.prototype又是直接给了一个新的对象obj2, 所以原来的box内部的__proto__还是指向obj1, 跟Box没关系,只是Box.prototype是指向obj2而已。

    一个小小的问题让我看了半天,看来对js的理解还是不够透彻。

  • 相关阅读:
    排序--插入排序(Insertion Sort)Java实现
    汉诺塔--递归和非递归 Java实现
    关于mysql使用utf8编码在cmd窗口无法添加中文数据的问题以及解决 方法二
    mysql在cmd中查询到的汉字乱码问题解决 方法一
    mysql绿色版安装以及遇到的问题
    关于按下回车键自动提交表单问题解决
    获取iframe引入页面内的元素
    ORACLE 中如何截取到时间的年月日中的年、月、日
    Jboss 7配置日志
    java中将科学技术发转为正常数据
  • 原文地址:https://www.cnblogs.com/Dn9x/p/4795773.html
Copyright © 2011-2022 走看看