这些天读了John Resig的《Secrets of JavaScript Ninja》,其中讨论到JS中实现继承的方案,非常有趣,自己探索了一下,形成了笔记,放到这里。

这个方案在Resig的博客上也有,虽然代码略微有点不一致,但核心思想是一样的,请戳 这里 。

<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
// call a immediate funciton,prevent global namespace from being polluted.
(function(){
// 这个initializing变量用于标识当前是否处于类的初始创建阶段,下面会继续详述
var initializing = false,
// 这是一个技巧性的写法,用于检测当前环境下函数是否能够序列化
// 附一篇讨论函数序列化的文章:http://www.cnblogs.com/ziyunfei/archive/2012/12/04/2799603.html
// superPattern引用一个正则对象,该对象用于验证被验证函数中是否有使用_super方法
superPattern = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; Object.subClass = function(properties){
// 当前对象(父类)的原型对象
var _super = this.prototype; // initializing = true表示当前处于类的初始创建阶段。
// this构造函数里会判断initializing的状态,如果为false则不执行Init方法。
// 事实上这也是非常需要的,因为在这个时候,我们需要的只是一个干净的虚构的构造函数,完全不需要其执行init函数,以避免污染。init方法只有在当前类被实例化的时候才需要被执行,而当前正执行继承行为,不应该执行Init方法。
initializing = true;
// 当前对象(父类)的一个实例对象
var proto = new this();
// 初始创建阶段完成,置initializing为false
initializing = false; // 在properties里提供的属性,作为当前对象(父类)实例的公共属性,供其子类实例共享;
// 在properties里提供的方法,作为当前对象(父类)实例的公共方法,供其子类实例共享。
for(var name in properties){
proto[name] = typeof properties[name] == 'function' && //检测当前提供的是否为函数
typeof _super[name] == 'function' && //检测当前提供的函数名是否已经存在于父类的原型对象中,如果是,则需要下面的操作,以保证父类中的方法不会被覆盖且可以以某种方式被调用,如果否,则直接将该函数赋值为父类实例的方法
superPattern.test(properties[name]) ? f//检测当前提供的函数内是否使用了_super方法,如果有使用_super方法,则需要下面的操作,以保证父类中的方法不会被覆盖且可以以某种方式被调用,如果没有用到_super方法,则直接将该函数赋值为父类实例的方法,即使父类原型中已经拥有同名方法(覆盖) // 使用一个马上执行的函数,返回一个闭包,这样每个闭包引用的都是各自的name和fn。
(function(name, fn){
return function() {
// 首先将执行方法的当前对象(子类的实例化对象)的_super属性保存到tmp变量里。
// 这是非常必要的, 因为this永远指向当前正在被调用的对象。
// 当C继承B,B继承A,而A\B\C均有一个dance方法且B\C的dance方法均使用了this._super来引用各自父类的方法时,下面这句操作就显得非常重要了。它使得在方法调用时,this._super永远指向“当前类”的父类的原型中的同名方法,从而避免this._super被随便改写。
var tmp = this._super; // 然后将父类的原型中的同名方法赋值给this._super,以便子类的实例化对象可以在其执行name方法时通过this._super使用对应的父类原型中已经存在的方法
this._super = _super[name]; // 执行创建子类时提供的函数,并通过arguments传入参数
var ret = fn.apply(this, arguments); // 将tmp里保存的_super属性重新赋值回this._super中
this._super = tmp; // 返回函数的执行结果
return ret;
};
})(name, properties[name]) :
properties[name];
} // 内部定义个名叫Class的类,构造函数内部只有一个操作:执行当前对象中可能存在的init方法
// 这样做的原因:新建一个类(闭包),可以防止很多干扰(详细可对比JS高级设计第三版)
function Class(){
// 如果不是正在实现继承,并且当前类的init方法存在,则执行init方法
// 每当subClass方法执行完毕后,都会返回这个Class构造函数,当用户使用new 方法时,就会执行这里面的操作
// 本质:每次调用subClass都新建一个类(闭包)
if(!initializing && this.init){
// 这是子类的初始化方法,里面可以定义子类的私有属性,公共属性请在上方所述处添加
this.init.apply(this, arguments);
}
} // 重写Class构造函数的prototype,使其不再指向了Class原生的原型对象,而是指向了proto,即当前对象(类)的一个实例
// 本质:一个类的原型是另一个类的实例(继承)
Class.prototype = proto;
// 为什么要重写Class的构造函数?因为这个Class函数,它原来的constructor指向的是Function对象,这里修正它的指向,使其指向自己。
Class.constructor = Class;
// 就是这个操作,使得每次调用subClass都会新生命的Class对象,也拥有subClass方法,可以继续被继承下去
// 本质:使得每次继承的子类都拥有被继承的能力
Class.subClass = arguments.callee;
// 返回这个内部新定义的构造函数(闭包)
return Class;
};
})(); var Person = Object.subClass({
init: function(isDancing) {
this.dancing = isDancing;
},
dance: function(){
console.log('i am a person,i dance.');
return this.dancing;
}
}); var Ninja = Person.subClass({
init:function(){ },
dance: function() {
console.log('i am an Ninja,i dance.');
this._super();
return;
},
swingSword:function(){
return true;
}
}); var Chileung = Ninja.subClass({
dance: function(){
console.log('i am Chileung.i dance.');
this._super();
return;
}
}); var p = new Person();
p.dance(); var n = new Ninja();
n.dance(); var c = new Chileung();
c.dance();
</script>
</body>
</html>
在博客园里也找到了一篇不错的有关这种继承方式的讨论,参见 这里

另外自己以前曾经也思考过Zakas提出的继承方案,文章见 这里

【深入JavaScript】一种JS的继承方法的更多相关文章

  1. JavaScript几种常见的继承方法

    1.call() 方法 call() 方法是与经典的对象冒充方法最相似的方法.它的第一个参数用作 this 的对象.其他参数都直接传递给函数自身 function Huster(name,idNum, ...

  2. 浅谈6种JS数组遍历方法的区别

    本篇文章给大家介绍一下6种JS数组遍历方法:for.foreach.for in.for of.. each. ().each的区别.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. ...

  3. JavaScript四种数值取整方法

    一.Math.trunc() 1.定义 Math.trunc()方法去除数字的小数部分,保留整数部分. 2.语法 Math.trunc(value) 3.示例 console.log(Math.tru ...

  4. js各继承方法的优缺点

    在js中有很多种继承的方法,下面总结这些方法的优缺点. ####1.原型链继承 优点: 非常纯粹的继承关系,实例是子类的实例,也是父类的实例 父类新增原型方法/原型属性,子类都能访问到 简单,易于实现 ...

  5. javascript四种类型识别的方法

    × 目录 [1]typeof [2]instanceof [3]constructor[4]toString 前面的话 javascript有复杂的类型系统,类型识别则是基本的功能.javascrip ...

  6. JavaScript 五种(构造方式)继承

    一.对象冒充 function Parent(username){ this.username = username; this.hello = function(){ alert(this.user ...

  7. javascript笔记——源生js实现each方法

    出处:http://www.lovejavascript.com/#!zone/blog/content.html?id=48 jquery里面有个each方法,将循环操作简化.便捷. 随后es出了个 ...

  8. 三种JS截取字符串方法

    JS提供三个截取字符串的方法,分别是:slice(),substring()和substr(),它们都可以接受一个或两个参数: var stmp = "rcinn.cn"; 使用一 ...

  9. cocos2d JS 源生js实现each方法

    javascript笔记——源生js实现each方法   出处:http://www.lovejavascript.com/#!zone/blog/content.html?id=48 jquery里 ...

随机推荐

  1. django系列8.4--django中间件的可应用案例, 限制请求次数与时间

    应用案例 1.做IP访问频率限制 某些IP访问服务器的频率过高,进行拦截, 比如每分钟不能超过20次 2.URL访问过滤 如果用户访问的是login视图,就允许请求 如果访问其他视图, 需要检测是不是 ...

  2. 基于SSH的网上体育用品商城-JavaWeb项目-有源码

    开发工具:Myeclipse/Eclipse + MySQL + Tomcat 项目简介: 网上体育商城的主要功能包括:前台用户登录退出.注册.在线购物.修改个人信息.后台商品管理等等.本系统结构如下 ...

  3. 深入了解java虚拟机(JVM) 第十一章 类的加载

    一.类加载机制概述 虚拟机把描述类的数据从class文件加载到内存并对数据进行效验,解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 二.类加载的机制 类加载的过程 ...

  4. “全栈2019”Java第一章:安装JDK11(Mac)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 文章原文链接 “全栈2019”Java第一章:安装JDK11(Mac) 下一章 “全栈2019”Java ...

  5. thinkphp3搜索结果分页

    公司的办公室搬到武昌,办公室水不好喝 还是乐百氏 娃哈哈的水我们oa用的tp3的一套oa,现在boss要求按状态 和类型(2个维度)来搜索案子 数量多,用 分页注意到初始的表单 input的name ...

  6. javascript获取wx.config内部字段解决微信分享

    转自:http://www.jb51.net/article/80679.htm 专题推荐:js微信开发_脚本之家 http://www.jb51.net/Special/879.htm 背景在微信分 ...

  7. mysql数据库中常用操作汇总

    一.查询数据库的基本信息: 1.    /* 查询数据库 ‘boss’ 所有表及注释 */SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema ...

  8. Centos7 自定义systemctl服务脚本

    序言篇: 之前工作环境一直使用Centos6版本,脚本一直在使用/etc/init.d/xxx:系统升级到Cento7后,虽然之前的启动脚本也可以使用,但一直没有使用systemctl 的自定义脚本. ...

  9. c++之选择排序和冒泡排序实现

     1.冒泡排序 冒泡排序就是通过对比前一个和后一个数的大小,按照规则进行顺序的调换.每一轮对比之后最大或者最小值都会浮到最上面或者沉到最低下. 如:对这一数组进行冒泡排序:int a[5]{34,12 ...

  10. Hadoop 3.1.2 下载安装和分布式搭建的准备

    官方有详细文档:https://hadoop.apache.org/docs/r3.1.2/hadoop-project-dist/hadoop-common/SingleCluster.html 我 ...