• Javascript模拟继承(赠送.net吐槽一段)


    首先吐槽一句,今年的就业形势很不乐观啊,特别是搞.net的(相对java),特特别是还没出校门没有正式工作经验的,找个实习很难,前些天接了个面试电话,上来就质疑我“你一个在校大学生怎么可能做了那么多项目呢,你的简历是真实的吗?这些项目你做的是核心工作吗?”,语气中充满了质疑,我只能生硬的回答着“嗯啊”,这个时候去解释或许太苍白了,我深知年轻人很难受到别人信任。当然了冷静下来想想,现在这个社会留给年轻人的机会本来就不多,就算你在大学里学了不少东西,做了不少东西,相对于前辈来讲还是有大差距的,经历点挫折是应该的嘛,不怨天不尤人,继续坚持下去吧。

    蛋疼的日子总要做点事的,最近想把自己写的一些js常用功能封装成自己的一个库,于是乎学习了一下jquery框架的整体架构,收获颇多,接着又看了看百度编辑器的核心js库,发现其中一段javascript模拟继承的代码,用的地方还挺多,闲得无聊分析一下吧。

    引起我注意的来自百度编辑器js库中的一段注释

      /**
         * 模拟继承机制,subClass继承superClass
         * @name inherits
         * @grammar UE.utils.inherits(subClass,superClass) => subClass
         * @example
         * function SuperClass(){
         *     this.name = "小李";
         * }
         * SuperClass.prototype = {
         *     hello:function(str){
         *         console.log(this.name + str);
         *     }
         * }
         * function SubClass(){
         *     this.name = "小张";
         * }
         * UE.utils.inherits(SubClass,SuperClass);
         * var sub = new SubClass();
         * sub.hello("早上好!"); ==> "小张早上好!"
         */

    要说大厂就是大厂,注释写的非常规范,可以让新人很快参与到项目中来。(顺便吐槽一句,.net开发者想进百度很难啊,内部有些办公系统也不招聘实习生,想进电商实现也很难啊,因为基本上没有.net平台了...)。

    建议先看一下prototype的用法(参考http://blog.sina.com.cn/s/blog_7045cb9e0100rtoh.html

    首先我们来看一个列子

    //定义一个父类
    function SuperClass() { this.name = "小李"; this.age = "15"; } //父类通过prototype给自己增加了一个hello方法 SuperClass.prototype = { hello: function (str) { console.log("hello:"+this.name + str); } }
    //父类通过prototype给自己增加了一个sex属性 SuperClass.prototype.sex
    = "男";
    //父类通过prototype给自己增加了一个指向一个对象(数组对象)的属性arr,这里强调一下,这里指向的是一个对象,待会测试有用。 SuperClass.prototype.arr
    = new Array("a", "b");
    //定义一个子类
    function SubClass() { this.name = "小张"; this.address = "北京"; }
    //将父类的方法属性克隆过来
    SubClass.prototype = new SuperClass();
    //创建一个子类对象
    var son = new SubClass();
    //这样我们的son遍具有了hello方法
    son.hello("你好");
    //我们生成另一个子类实例,改变name和arr
    var son2 = new SubClass();
    son2.name="小红"; son2.arr.push(
    "cc"); console.log(son.name);//值未变
    console.log(son.arr);//输出a,b,cc也就是说父类中的属性如果指向的是对象,则子类的实例将会共享这个对象。

    上面的列子中 SubClass.prototype = new SuperClass();   这句起到了关键的作用,它把父类的方法属性克隆给了子类。但是会带来一个问题,那就是假如子类的定义中使用了js框架中流行的构造函数/原型方式,如下:

       function SubClass() {
                this.name = "小张";
                this.address = "北京";
            }
      SubClass.prototype.add = function () {
                console.log("add:"+this.name);
            }

    这就是传说中的联合创建类的方法,就是用构造函数/原型方式就可以像其他程序设计语言一样创建对象,用构造函数定义对象的非函数属性,用原型方式定义对象的方法。 很多js框架中都在用这种方法,这种方法效率较高,节约内存。

    然而当在子类定义之后写上 SubClass.prototype = new SuperClass();以后,会覆盖掉自己定义的add方法,这样子类的这句定义

     SubClass.prototype.add = function () {

                console.log("add:"+this.name);

    }

    就必须写到SubClass.prototype = new SuperClass(); 之后了。这样显然给我们使用带来了麻烦,每次定义子类这种用法的时候还得考虑一个顺序问题,实在不方便。我们看看百度编辑器的js核心库是怎么解决的

    为了分析方便,我把它的js模拟继承的代码抽离出来,原来一些以json方式组织的函数单独放到一个新的html页面里做测试。以下是我抽离出来的和模拟继承有关的代码:

     //定义一个父类
            function SuperClass() {
                this.name = "小李";
                this.showMsg = function () {
                    alert("baseClass::showMsg");
                }
              
            }      
          
            SuperClass.prototype = {
                hello: function (str) {
                    console.log(this.name + str);
                }
               
            }
            SuperClass.prototype.sex = "男";
            SuperClass.prototype.arr = new Array("a", "b"); 
            //定义子类
            function SubClass() {
                this.name = "小张";
    
            }
            //子类通过联合创建方式增加了add方法
            SubClass.prototype.ddd = function () { console.log(this.name); }   
            //可以在定义完成之后,在需要继承的时候写上一下语句来开始继承操作 
            inherits(SubClass, SuperClass);
            //生成一个子类实例
            var sub = new SubClass();
            sub.hello("早上好!");//父类的hello可以使用
            sub.ddd(); //子类的ddd方法可以使用了     
            sub.arr.push("cc");
            var sub1 = new SubClass();      
            console.log(sub1.arr);//sub1和sub共享了arr,需注意。

    相应的extend,inherits和makeInstance方法

            //将原型s中的属性复制给一个对象t
            function extend(t, s, b) {
                if (s) {
    //                console.log(s);
                    for (var k in s) {                   
    //下面用到了hasOwnProperty,用来判断一个对象是否有你给出的属性或对象
    if (!b || !t.hasOwnProperty(k)) { t[k] = s[k]; } } } return t; } function inherits(subClass, superClass) { var oldP = subClass.prototype, newP = makeInstance(superClass.prototype); //返回父类由原型方法生成实例对象,这里并没有返回整个父类对象实例,而是根据父类原型生成了一个对象,这样父类构造函数中的成员屏蔽掉了,子类无法继承。 console.log(newP); extend(newP, oldP, true); //通过这一步,子类在原型中定义的属性赋给了父类原型生成的对象 subClass.prototype = newP;//通过这一步,子类原型被重新构造,包括了自己原来的属性和父类原型中的属性。 return (newP.constructor = subClass); } function makeInstance(obj) { var noop = new Function(); noop.prototype = obj; obj = new noop; noop.prototype = null; return obj; }
    这里要说一句,这篇文章介绍的模拟继承方法只能将父类原型中的属性,比如上面的hello方法可以继承给子类,或者父类原型再添加一个性别属性比如SuperClass.prototype.sex = "男";这里的sex同样可以传递给子类,但是父类构造函数中的成员无法继承给子类,子类必须重新定义。也就是说父类构造函数中定义的属性可以认为是“private”的,父类原型中定义的是”public“的,所以如果父类的属性想让子类继承,最好定义到原型中。这时特别要注意如果父类原型中的成员指向一个对象时,比如 SuperClass.prototype.arr = new Array("a", "b"); 所有子类的实例将会共享这个arr属性。

    总结它的这个逻辑也就一句话,把子类原型中的成员给了父亲原型的一个实例对象,这个实例对象得到了扩充,然后清空子类原型,最后把这个扩充的对象中的成员克隆给子类原型。

       好了,扯淡了半天把自己都扯晕了,我是有多无聊啊。赶紧来个单位把我这妖孽收了吧。

  • 相关阅读:
    Software_Kingjdk配置java
    SSH中的分页错误:java.lang.Integer cannot be cast to java.lang.Long
    struts2中文件上传出错!
    Navicat Premium(导航猫数据库管理)navicat091_premium_cs + instantclientbasic
    org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in readonly mode (FlushMode.NEVER/MANUAL): Turn your Ses
    OAS2Sh项目中:java.lang.IllegalArgumentException: id to load is required for loading
    python之封装
    python函数中的装饰器
    OSI七层模型
    函数
  • 原文地址:https://www.cnblogs.com/srszzw/p/3440295.html
Copyright © 2020-2023  润新知