• Javascript讲解系列之一 Prototype原型链


       以前没有写博客的习惯,许多的技术积累都是自己稍微总结一下,很少共享,并非自私,而是工作比较忙,前几天接到一个电话面试不理想,才发现公司所用的DOJO并不被外面广泛接受,故而决定把自己所学分享出来,为夯实基础,也为与外界交流思想,形成一种渠道,如需联系,请发送至邮箱:diydyq@126.com。

       今天写Javascript系列之第一篇:Prototype原型链。在软件园里随便拉一个码农估计都会写JS,大部分也知道JS是基于原型的语言,但是如果问及JS原生对象(Object,Function,Array,Date等)的这个原型链长什么样子?估计能回答出来的人就少了,我开始也非常糊涂,后来决心一定要好好搞一下,花了2天功夫基本算是明白了,分享如下:

       测试环境:Firefox、Firebug;

       为做好铺垫,按顺序解释如下概念:

       1)类型、原生类型、对象类型(types、primitive types、object types)

       不像我们在学习JAVA时,被告知JAVA是完全OOP的语言:class是一类具有共同特点的物体的抽象,object是某个class下具体的一个实例,Object类是所有类的顶层父类,对Java的认知是从类与对象开始的;Javascript则不然,它是从类型(type)开始,在各类语言中遇到的number,string, boolean, object, function,array等都属于类型。

       这些类型在JS中分为两大类:原生类型与对象类型,原生类型包括:number,string, bool, null, undefined;剩下的非原生类型对象都属于对象类型,包括:object, array, function等,这里的object专指具有属性(attribute)的对象,在Firebug中的代码示例如下:

    function log(){ console && console.log.apply(console, arguments); };
    var opts = Object.prototype.toString;
    // 1) primitive types log(typeof 1); // number log(typeof ""); // string log(typeof false); // boolean log(typeof undefined); // undefined log(typeof null); // object null是个特列,属于原生类型; log(null instanceof Object); // false // 2) object types. log(typeof new Object); // object log(typeof new Function); // function log(typeof new Array); // object log(opts.call(new Object)); // [object Object] log(opts.call(new Function)); // [object Function] log(opts.call(new Array)); // [object Array]

       判断某个值是什么大的类型没有意义,往往需要判断它是什么原生类型或者对象类型:判断原生类型,可以使用typeof关键字;判断对象类型,可以使用toString()方法;

       2)prototype与__proto__的区别

       两者都是对象类型的属性,并非所有的对象类型都有prototype属性,一般只有function对象才有prototype属性(除非主动赋值),它指向的是一个对象,将来会被多个该function的实例所继承(或者说该对象处于多个实例的原型链上);__proto__才是真正的原型链的实际指针,然而许多浏览器并不对外公开这个属性,Firefox暴露出这一属性,仅供开发人员理解,但不推荐开发中使用。下面我们用一段代码来做验证:

    // 1) prototype属性:一般只有function对象拥有
    log((new Object).prototype);                    // undefined
    log([].prototype);                              // undefined
    log((new Function).prototype);                  // anonymous {}
                                                    // Function, Object, Array是function对象
    log(Function.prototype);                        // function()
    log(Object.prototype);                          // Object {}
    log(Array.prototype);                           // []
    // 2) __proto__属性:指向该对象原型链的上一端
    log((Object.prototype).__proto__);              // null
    log((Function.prototype).__proto__);            // Object {}
    log(Object.__proto__);                          // function()
    log(Function.__proto__);                        // function()
    // function对象Company的prototype属性所指的对象处于实例对象的原型链上
    var Company = function(name){
        this.name = name;
    };
    var c1 = new Company("IBM");
    var c2 = new Company("Alibaba");
    console.log(c1.__proto__ == Company.prototype); // true
    console.log(c2.__proto__ == Company.prototype); // true

       上面的示例我们确认了__proto__才是原型链中对象之间从下到上的联系的桥梁,那么既然是链总该有个头吧?要是一直找不到头,就成死链了,在JAVA里所有对象都会继承来自最顶层父类Object的方法一样,如:toString方法,JS中会继承哪些方法呢?

       3)原型链的最顶端

       既然__proto__是链的索引,那么我们是否可以辛苦测试一下常用的对象呢?

    // 原型链的顶端
    log((Object.prototype).__proto__);                                      // null
    log(Function.prototype.__proto__ == Object.prototype);                  // true
    log(Object.__proto__            == Function.prototype);                 // true
    log(Function.__proto__          == Function.prototype);                 // true
    log(Array.__proto__             == Function.prototype);                 // true
    log(Company.__proto__           == Function.prototype);                 // true
    log(Object.__proto__            == Function.prototype);                 // true
    log(Company.prototype.__proto__ == Object.prototype);                   // true
    log(c1.__proto__                == Company.prototype);                  // true

       经过上面的比较后,我们基本就可以画出这个原型链顶端的样子了, 如下图:

    wKiom1L8wePA8j9ZAAozkkWMaaw051.jpg

     

       4)了解原型链最顶端的意义

       意义似乎应该放在前面讲更突出重要性,就当不求甚解吧,个人理解有如下意义:

       A) 清楚对象的继承结构,知道它有哪些父类(父类:指的是该对象原型链向上方向的对象);

       B) 了解并调用父类的方法,不会混淆功能;

       C) 多个对象共享原型链的某一段时,方便调试;

       针对A好处,我们可以更好的理解instanceof关键字的作用;

       针对B好处,我们可以调用不同父类的方法完全不同的判断需求,比如:Function.prototype.toString.call(obj)方法用于输出function对象的定义代码,Object.prototype.toString.call(obj)方法用于输出该对象所属的object类型;

       针对C好处,这个便于理解复杂JS框架中对象的内存管理模型,比如:DOJO框架,这个以后会提及。

       刚才我们用__proto__获取原型链,有没有一种通用的方式呢?那么在图中有个方法可以做到:

       Object.getPrototypeOf(obj),(未测所有浏览器,Firefox, IE10可以)。

     

       关于链的样子就讲完了,下期有时间来讲Javascript是否可以模拟OOP;

     

  • 相关阅读:
    MYSQL优化
    linux 基础知识 之基础系统管理2
    mysql数据库读写分离+高可用
    Varnish代理缓存服务器
    tomcat
    Memcached, Redis, MongoDB区别、特点、使用场景
    session共享
    基于docker的zabbix服务搭建
    php-fpm 启动后没有监听端口9000
    学习网站
  • 原文地址:https://www.cnblogs.com/diydyq/p/3755930.html
Copyright © 2020-2023  润新知