对javascript继承的理解


Posted in Javascript onOctober 11, 2016

由于javascript原生是不支持类的(ES6已经支持class与extends),更不用谈继承、多态了,为了模拟出一些其它面向对象编程语言的这些特性,有好多大牛写了给出了实现方式,看了John Resig的《Simple JavaScript Inheritance》这篇文章,深深被折服了,原来短短几十行javascript也可以这么强大、优雅,下面以我的理解方式来解读下。

主要实现了继承、访问父类的重名方法(这里的实现方式太妙了),但遗憾的是不能实现成员变量/函数的隐藏。

(function(){
  //设置标志位,是new A()过程中还是 B=A.extends({/*   */})过程中;
  var initializing = false,
      //fnTest 可取结果为俩正则对象 /\b_super\b/与 /.*/
      //当正则的test方法参数支持自动调用toString()方法时取前面那个
      fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
    
  // 创建一个全局的 Class对象
  this.Class = function(){};
    
  // 创建继承函数
  Class.extend = function(prop) {
    //此处把_super指向父类的prototype,属性继承时需要用其判断父、子是否有同名方法
    var _super = this.prototype;
      
    //开始B=A.extends({/*   */});
    initializing = true;
    //实例化父类,并把父类的实例方法及属性给prototype
    var prototype = new this();
    initializing = false;
    //结束B=A.extends({/*   */});
      
    // 遍历用户传入的用于构建子类的对象
    //处理的地方包括:
    //1、属性直接存到prototype上
    //2、方法中没通过this._super()调用父类中的同名方法,则直接把该方法存到prototype上
    //3、方法中有通过this._super()调用父类中的同名方法,则把如下过程包裹成一个函数存到prototype上:
    //   把this._super指向父类的同名方法,然后再调用子类的该方法并返回执行结果
    for (var name in prop) {
      // 循环体中看起来略微复杂,是整个代码的精华所在
      //简化下此过程就是  v = a && b && c ? d : e; 等同于 v = (a && b && c) ? d : e
      //该过程中主要运用的就是逻辑运算中的短路运算 a,b,c全为true则v=d,否则v=e
      //a中判断prop[name]是否是函数,b中判断父类中是否也有同名的name函数,c主要判断name函数中是否有调用父类的同名方法(即调用了this._super())
      //d就是a,b,c同时满足的时候,也就是说:name是函数,且name函数存在与父类中,且子类的name函数需要调用了父类的同名函数
      //若a,b,c中有一项不满足则直接把prop[name]给prototype[name]
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          //首先,先决条件决定了prototype[name]是个函数,所以先包裹一个函数返回
          return function() {
            //作者这里备份,然后调用fn后又还原this._super
            //由于return的是一个function,具有延时调用的作用 所以在子类调用fn时this始终指向子类本身
            //而这里的_super是父类的_super,与this._super并无关系,所以备份应该是多余的
            //var tmp = this._super;
            //this._super指向与fn(即prop[name])同名的父类方法,方便fn内部调用
            //这里是实现子类中通过this._super()调用父类同名函数的关键
            this._super = _super[name];
            //此时再调用子类,子类里面的this._super已经指向了父类同名的函数,即_super[name]
            var ret = fn.apply(this, arguments);   
            //this._super = tmp;
            //返回执行结果
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
      
    //此“Class”与外头那个“Class”是两个东西
    //这个Class实为子类的构造函数
    function Class() {
      //不是A.extends({/*   */})过程中
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
      
    //前面处理好的prototype绑定给子类的prototype
    Class.prototype = prototype;
      
    //修正构造函数
    Class.prototype.constructor = Class;
    
    //赋予子类可被继续继承的功能
    Class.extend = arguments.callee;
      
    return Class;
  };
})();

如果想更深入了解js继承,请继续往下查看文章

Javascript 相关文章推荐
使用Javascript接收get传递的值的代码
Nov 30 Javascript
jquery实现的可隐藏重现的靠边悬浮层实例代码
May 27 Javascript
使用js对select动态添加和删除OPTION示例代码
Aug 12 Javascript
jQuery实现表格颜色交替显示的方法
Mar 09 Javascript
jquery中实现时间戳与日期相互转换
Apr 12 Javascript
纯js模仿windows系统日历
Feb 04 Javascript
AngularJS使用ng-class动态增减class样式的方法示例
May 18 Javascript
详解为Bootstrap Modal添加拖拽的方法
Jan 05 Javascript
vue实现树形菜单效果
Mar 19 Javascript
如何使用proxy实现一个简单完整的MVVM库的示例代码
Sep 17 Javascript
vue 授权获取微信openId操作
Nov 13 Javascript
微信小程序实现日历小功能
Nov 18 Javascript
Javascript动画效果(3)
Oct 11 #Javascript
JavaScript实现自动切换图片代码
Oct 11 #Javascript
Javascript动画效果(2)
Oct 11 #Javascript
Javascript动画效果(1)
Oct 11 #Javascript
原生Javascript和jQuery做轮播图简单例子
Oct 11 #Javascript
jQuery progressbar通过Ajax请求实现后台进度实时功能
Oct 11 #Javascript
javascript之with的使用(阿里云、淘宝使用代码分析)
Oct 11 #Javascript
You might like
Apache2 httpd.conf 中文版
2006/12/06 PHP
PHP通过加锁实现并发情况下抢码功能
2016/08/10 PHP
基于jquery的button默认enter事件(回车事件)。
2011/05/18 Javascript
Jquery中Ajax 缓存带来的影响的解决方法
2011/05/19 Javascript
面向对象的Javascript之三(封装和信息隐藏)
2012/01/27 Javascript
使用indexOf等在JavaScript的数组中进行元素查找和替换
2013/09/18 Javascript
多种方法实现JS动态添加事件
2013/11/01 Javascript
javascript实现控制div颜色
2015/07/07 Javascript
全面解析Bootstrap布局组件应用
2016/02/22 Javascript
JavaScript基本类型值-Number类型
2017/02/24 Javascript
vue中计算属性(computed)、methods和watched之间的区别
2017/07/27 Javascript
Angular2 父子组件通信方式的示例
2018/01/29 Javascript
Javascript 编码约定(编码规范)
2018/03/11 Javascript
Vue中"This dependency was not found"问题的解决方法
2018/06/19 Javascript
JavaScript事件冒泡与事件捕获实例分析
2018/08/01 Javascript
js实现弹出框的拖拽效果实例代码详解
2019/04/16 Javascript
JavaScript HTML DOM元素 节点操作汇总
2019/07/29 Javascript
[01:13]DOTA2群星解读国服召集令 一起说出回归的理由
2013/07/17 DOTA
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Python发送Email方法实例
2014/08/21 Python
Python数组定义方法
2016/04/13 Python
Python实现返回数组中第i小元素的方法示例
2017/12/04 Python
把csv文件转化为数组及数组的切片方法
2018/07/04 Python
使用python爬取微博数据打造一颗“心”
2019/06/28 Python
利用python实现短信和电话提醒功能的例子
2019/08/08 Python
selenium WebDriverWait类等待机制的实现
2020/03/18 Python
python怎么删除缓存文件
2020/07/19 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
adidas菲律宾官网:adidas PH
2020/02/07 全球购物
介绍Ibatis的核心类
2013/11/18 面试题
销售实习自我鉴定
2013/12/07 职场文书
个人自我剖析材料
2014/02/07 职场文书
商业门面租房协议书
2014/11/25 职场文书
大队委员竞选演讲稿
2015/11/20 职场文书
CSS3 天气图标动画效果
2021/04/06 HTML / CSS
pytorch中Schedule与warmup_steps的用法说明
2021/05/24 Python