对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 OOP类与继承
Nov 15 Javascript
javascript 嵌套的函数(作用域链)
Mar 15 Javascript
jQuery 表单验证扩展(三)
Oct 20 Javascript
js获取url中"?"后面的字串方法
May 15 Javascript
jQuery获取标签文本内容和html内容的方法
Mar 27 Javascript
判断数组的最佳方法(推荐)
Oct 11 Javascript
jQuery实现的电子时钟效果完整示例
Apr 28 jQuery
Vue slot用法(小结)
Oct 22 Javascript
6行代码实现微信小程序页面返回顶部效果
Dec 28 Javascript
Vue3.0中的monorepo管理模式的实现
Oct 14 Javascript
JS错误处理与调试操作实例分析
Apr 13 Javascript
vue3.0搭配.net core实现文件上传组件
Oct 29 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
ThinkPHP字符串函数及常用函数汇总
2014/07/18 PHP
在Debian系统下配置LNMP的教程
2015/07/09 PHP
PHP实现图片不变型裁剪及图片按比例裁剪的方法
2016/01/14 PHP
PHP内核学习教程之php opcode内核实现
2016/01/27 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
PHP判断是否是微信打开还是浏览器打开的方法
2019/02/27 PHP
广告切换效果(缓动切换)
2009/05/27 Javascript
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
ASP.NET中AJAX 调用实例代码
2012/05/03 Javascript
NodeJs中的非阻塞方法介绍
2012/06/05 NodeJs
深入理解Javascript中的循环优化
2013/11/09 Javascript
js数组的操作指南
2014/12/28 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
2015/02/13 Javascript
JS实现可点击展开与关闭的左侧广告代码
2015/09/02 Javascript
JS实现可展开折叠层的鼠标拖曳效果
2015/10/09 Javascript
jQuery绑定事件on()与弹窗的简要概述
2016/04/27 Javascript
详解nodejs与javascript中的aes加密
2016/05/22 NodeJs
jQuery的Each比JS原生for循环性能慢很多的原因
2016/07/05 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
js Date()日期函数浏览器兼容问题解决方法
2017/09/12 Javascript
vue项目中仿element-ui弹框效果的实例代码
2019/04/22 Javascript
vue实现放大镜效果
2020/09/17 Javascript
JavaScript实现鼠标经过表格某行时此行变色
2020/11/20 Javascript
JavaScript实现京东快递单号查询
2020/11/30 Javascript
详解Python安装scrapy的正确姿势
2018/06/26 Python
对python遍历文件夹中的所有jpg文件的实例详解
2018/12/08 Python
节日快乐! Python画一棵圣诞树送给你
2019/12/24 Python
canvas 实现 github404动态效果的示例代码
2017/11/15 HTML / CSS
html5 canvas手势解锁源码分享
2020/01/07 HTML / CSS
德国大型和小型家用电器网上商店:Energeto
2019/05/15 全球购物
西安众合通用.net笔试题
2013/03/18 面试题
保卫科工作岗位职责
2014/03/01 职场文书
女生节标语
2014/06/26 职场文书
法人代表身份证明书及授权委托书
2014/09/16 职场文书
2014年辅导员工作总结
2014/11/18 职场文书
css3实现背景图片颜色修改的多种方式
2021/04/13 HTML / CSS