• 轻松搞定javascript原型链 _proto_ 恒


    //如有错误或不同观点,欢迎批评与讨论!

    首先,prototype出现的目的,是为了解决 代码重用 的问题 , prototype 相当于是在内存上划分出一个公共的区域, 专用于存放 实例化对象 的相同方法或属性, 一份代码,人人可用;

    为方便理解,我们可以先把prototype 当作是CSS中的 class,在prototype上加方法和属性,那么其它对象就会拥有这些方法和属性, 但这些代码紧有一份!

    <script>
    function Person()
    {
        this.name = '张三'; 
        this.id = function (){ alert('身份证') };
    }
    Person.prototype.say = function (){ alert('说话'); }
    
    var P1 = new Person();
    var P2 = new Person();
    
    console.log(P1);
    console.log(P2);
    console.log(P1.name === P2.name);    //true
    console.log(P1.id === P2.id);    //false
    console.log(P1.say === P2.say);    //true
    </script>
    View Code

    /*---------------------------------------------------------------*/

    运行上面代码,从控制台中可以看出:

    1.name, id 都是直接放在 new出来的对象上的, 他们的name的比较是相等的(因为字符串是基本类型,所以为true),而id比较 是false,这是因为 function 是复合数据类型,比较的是引用值,这两个 id 分别属于两个不同的对象, 引用不一样,所以为false;

    2.我们直接 P1.say() 是可以运行的,但是从控制台可看出,P1和P2并没有say这个方法,这个方法其实是属于 Person.prototype 这个对象的,那为什么P1,P2可以使用这个方法呢?请看下图

    3.从控制台中我们还可以看到这样的个东东:_proto_ ; 它就是JS的 原型链 ,我们是访问不了它的, 但是可以在控制台中看到它, 其实 _proto_ 就是将 实例对象 P1、P2 和 类(构造函数)建立起一个联系,通过这个 原型链 可以找到Person.prototype这个内存公共空间里的 所有公共方法和属性; 从上图可以看出, say这个方法正是在里面,  而这个constructor是哪里来的呢? 这个是当我们定义Person函数的时候, 浏览器自动给我们添加的, 并且指向 Person它自己:  Person.prototype.constructor = Person; 这个属性很容易在不经意间被我们修改, 出现这种情况时我们需要手动修正一下, JQ也是这样处理的, 详情请看最后面的补充, 现在继续上面的讨论;

    4.从上图中我们还可以看到 _proto_ :Object,   原型链 又将P1, P2 和 Object类联系了起来, 这个,P1,P2 就可以使用 Object.prototype 这个内存公共空间里的 所有公共方法和属性,虽然Person.prototype上没有这些方法和属性, 我们 alert( P1.hasOwnProperty('id') ) 是可以得到true的,因为 它们在同一条原型链上。

    从上图还可以看出, 浏览器也给Objcet加了这样的个属性: Object.prototype.constructor = Object; 那为什么 P1.constructor 会是Person, 而不是Object呢,  因为原型链是 这样的   P1  _proto _  Person   _proto _  Object , P1在Person.prototype处找到了constructor这个属性,就不会继续往下找,只有找不到的时候才往下找。

    5.原型链的尽头是Object,   从上头可以看出,没有  _proto_ 再连接到别的地方了。

    6.所以,只要是在同一原型链上,实例化对象就可以使用这些方法和属性,如果有重复的方法或属性, 距离近的会覆盖距离远的。

    下面我做了个小图给大家参考参考 :

    -如果图片看不清,请单击鼠标右键,复制图片地址,粘贴在浏览器地址栏上打开------------------------------------------------------------------------------------------------------------------------------------------------------

    a.上面可看出,  房子嘛,  不是说你一出生就有的,  自己 没有可以先住老爸的, 如果老爸没有嘛,  老爸他哥有,  你出门在外,  也可以先去住着先的,   再没有嘛再去别的亲戚家住下先,     最远的尽头是 Object,

    b.如果你老爸买房子了,   那你就别去你大伯家住啦,   你就去你老爸那住,

    c.如果你有能力啦,买房子啦, 就自己搬出来住啦!(相当于加 this.sleep ,优先级高于 prototype上的sleep,和css中的 id相似)

    补充:

    上面说到的我们会在不经意间会修改,Person.prototype.constructor这个属性,是哪种情况呢?

     1 <script>
     2 function Person()
     3 {
     4     this.name = '张三'; 
     5     this.id = function (){ alert('身份证') };
     6 }
     7 //Person.prototype.say = function (){ alert('说话'); }
     8 Person.prototype = { say: function (){ alert('说话') }}
     9 
    10 var P1 = new Person();
    11 console.log(P1.constructor)
    12 </script>
    View Code

    Person.prototype也是对象,所以可以改成下面的写法,但是改成这样的写法后,我们会看到,P1.constructor 竟然变成了 function Object() { [native code] },  怎么会变成  Object 呢?

    是这样的,第一种写法, 是给 Person.prototype 对像添加属性;  而第二种写法, 是直接把一个对象{ }覆盖了 Person.prototype 这个对像,   这种写法的{ }对象是 Object 实例出来的,  所以嘛,  这个 P1.constructor当然就是Object啦;

    像上面的,你老爸把房产证卖给都给Objcet了,虽然你还住着(别人还没赶你走~~), 你说这个房子的主人是谁?

    所以我们需要手动修正一下,Person.prototype.constructor = Person;

    下图可以看到,JQ也是这样处理的:

     

  • 相关阅读:
    jQuery+ThinkPHP+Ajax实现即时消息提醒功能
    依赖注入(DI)
    控制反转(IoC)
    ajax以base64上传图片到django
    python 多进程、多线程、协程
    python3 实现tcp/udp局域网通信
    同源策略与跨域访问
    nginx+uwsgi阿里云ubuntu服务器上简单部署flask RESTful风格项目
    python3 实现 websocket server 解决中文乱码
    python IO 多路复用 epoll简单模型
  • 原文地址:https://www.cnblogs.com/Ivangel/p/3681312.html
Copyright © 2020-2023  润新知