`
Mossad
  • 浏览: 82167 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Classify源码解析

阅读更多

        Classify是一个小巧、简单的JavaScript继承框架,官网上的资料非常简洁,一共才6个api,常用的也就4个,可以很快的看完并使用,麻雀虽小但五脏俱全,它的作用却是非常强大的,能够帮助用户使用JavaScript编写出简洁、优雅、易于管理和维护的继承框架,以下是我对其的源码解析,都写在注释上了,其中标注有*_*符号的是我觉得比较重要的点,大家可以参考参考:

(function() {

	// ----------------------------------
	// Constants
	// ----------------------------------

	var FUNCTION = 'function', STRING = 'string',

	// ----------------------------------
	// Internal Properties
	// ----------------------------------

	// The namespace where the keyword methods will be attached to.
	// 关键方法所在的命名空间,在浏览器中就是Window,包括:def, classify, module, include, extend, alias。
	namespace = this,

	// The current scope to define Classes, Modules, and Methods on.
	// 定义类、模块和方法时的上下文。
	currentObject = namespace,

	// The current Class to define Methods on.
	// 定义方法时所在的类。
	currentClass = null,
 
	// Flag to signal when we are initializing a superclass during inheritance
	// 一个在实现继承时会被用到的临时标识位,下面会讲到它的用途。
	inheriting = false;

	// ----------------------------------
	// Internal Methods
	// ----------------------------------

	// Builds a new Class, with optional inheritance.
	// 定义一个类,可以选择继承另一个类作为它的父类。
	function buildClass(name, superclass) {
		// *_*这个就是使用Classify定义的类的本质,就是一个名为Class的很简单的一个函数。
		function Class() {
			/**
			 * inheriting标识位在这里被使用,首先我们可以通过定义一个名为initialize的方法来作为类的构造函数,
			 * 而当要创建一个类并指定了它的父类时,会通过Class.prototype = new superclass()来创建一个父类的实例并将其赋给
			 * 子类的prototype属性来建立继承的关系,此时被创建出来的父类对象是不应该走它的initialize方法的,所以这里可以
			 * 通过控制inheriting的true/false来区分一个类被创建时是应该走initialize构造函数(正常使用时)还是不应该走initialize构造函数(继承时)。
			 */
			if (!inheriting && typeof this.initialize == FUNCTION) {
				this.initialize.apply(this, arguments);
			}
		}

		if (superclass != null) {
			inheriting = true;//开启标志位。
			Class.prototype = new superclass();
			for ( var method in superclass) {//*_*子类会继承父类的类方法。
				if (typeof superclass[method] == FUNCTION) {
					namespace.def(Class, method, superclass[method]);
				}
			}
			inheriting = false;//关闭标志位。
		}

		Class.superclass = superclass;//*_*将父类的引用保存到子类的superclass属性中,这个非常有用!
		Class.prototype.constructor = Class;//如果有继承,那么将prototype的constructor指向正确的值。
		Class.prototype.toString = function() {//添加实例对象的toString方法。
			return '[object ' + this.constructor.toString() + ']';
		};

		addName(currentObject, Class, name);//添加类方法toString,一个有用的方法。

		return Class;
	}

	// Builds a new module.
	// *_*创建一个新的模块,其实就是一个带toString方法的简单对象。
	function buildModule(name) {
		return addName(currentObject, {}, name);
	}

	// Adds a toString method that returns the name of the object
	// 添加一个toString方法,主要用到了闭包。
	function addName(currentObject, object, name) {
		object.toString = function(includeModules) {
			if (includeModules === false || currentObject == null || currentObject === namespace) {
				return name;
			} else {
				return currentObject + '.' + name;
			}
		};
		return object;
	}

	// Add the given methods to the object.
	function addDefinition(withClass, withObject, definition) {
		if (withObject == null || definition == null) {
			return;
		}

		// 将currentClass和currentObject临时存起来。
		var oldClass = currentClass, oldObject = currentObject;

		// 改变上下文。
		currentClass = withClass;
		currentObject = withObject;

		if (typeof definition == FUNCTION) {
			definition.call(withObject);//进入类定义方法。
		} else {
			for ( var name in definition) {
				if (!(/^(constructor|prototype|toString|valueOf)$/).test(name)) {
					namespace.def(name, definition[name]);
				}
			}
		}

		// 恢复上下文。
		currentClass = oldClass;
		currentObject = oldObject;
	}

	// If necessary add a `callSuper` method to access the superclass's method.
	// *_*子方法中的callSuper能够访问父类方法的本质,其实就是通过一个闭包来代理子方法,闭包中保存了子方法和父方法的原实现。
	function addCallSuper(definition, superDefinition) {
		if (typeof superDefinition == FUNCTION && callsSuper(definition)) {
			return function() {
				//如果子类中恰好也定义了一个callSuper方法,那么暂时先将它保存起来以避免冲突。
				var defArgs = arguments, oldSuper = this.callSuper, result;

				this.callSuper = function() {
					//如果callSuper调用时指定了参数,那么就使用指定的参数调用父方法,否则就默认使用原参数,非常地灵活方便。
					return superDefinition.apply(this, arguments.length ? arguments : defArgs);
				};

				result = definition.apply(this, defArgs);
				this.callSuper = oldSuper;//还原callSuper。

				return result;
			};
		}

		return definition;
	}

	// Test to see if a function contains a call to `callSuper`
	// 测试子方法中是否调用了父方法。
	function callsSuper(method) {
		return (/\bthis\.callSuper\b/).test(method.toString());
	}

	// ----------------------------------
	// Public Methods
	// ----------------------------------

	// Defines a new method. The method will be defined on the _current scope_,
	// which will be either the `window`, a Class, or Module. Within the method definition,
	// `this` will refer to the _current scope_. Optionally, you can set the object to
	// define the method on as the first argument.
	/**
	 * 定义一个方法。该方法会被定义在当前上下文中,可能是window、一个类或一个模块。在方法定义中,this会
	 * 指向当前上下文。你也可以在第一个参数中指定方法被定义的对象。
	 */
	namespace.def = function(object, name, definition) {
		// 参数归位,下面很多地方都这样使用。
		if (definition == null) {
			definition = name;
			name = object;
			object = currentClass || currentObject;//方法会被定义在当前类或当前对象中。
		}

		object[name] = addCallSuper(definition, object[name]);

		return object[name];
	};

	// Creates a new Class. The Class will be defined on the _current scope_,
	// which will be either the `window` or a Module. Optionally you can pass in a
	// Superclass as the first argument.
	// 定义一个类。该类会被定义在当前上下文中,可能是window或一个模块。你也可以在第一个参数中指定它的父类。
	namespace.classify = function(superclass, object, definition) {
		if (definition == null) {
			definition = object;
			object = superclass;
			superclass = null;//无父类。
		}

		//这里可以通过设置一个字符串参数来创建一个新类或者直接获取一个已存在的类。
		if (typeof object == STRING) {
			if (currentObject[object] == null) {//如果类之前没被定义过,那么定义一个。
				currentObject[object] = buildClass(object, superclass);
			}
			object = currentObject[object];
		}
		
		//甚至可以直接指定某个已经存在的类进行增强。
		addDefinition(object.prototype, object, definition);//开始创建类。

		return object;
	};

	// Creates a new Module. Modules can be used as namespaces for other Modules
	// and Classes. They can also be used as a collection of method definitions
	// to be included into other Classes.
	/**
	 * 创建一个模块。模块不仅可以作为其他模块和类的命名空间,还可以在其中定义一系列方法后引入到其他类中作为类方法或成员方法使用。
	 */
	namespace.module = function(object, definition) {
		if (typeof object == STRING) {
			if (currentObject[object] == null) {//创建一个新模块
				currentObject[object] = buildModule(object);
			}
			object = currentObject[object];//如果currentObject[object] !== null,那么可以直接获取一个已存在的模块
		}

		/**
		 * 指定第一个参数为null,使得definition中的新方法会被定义在当前模块中,
		 * 指定第二个参数为当前模块,使得definition中的新类和新模块会被定义在当前模块中。
		 */
		addDefinition(null, object, definition);

		return object;
	};

	// Includes the given Module methods into either the current Class or, optionally,
	// the given Class Definition. The included methods will be available on the instance of the Class.
	/**
	 * 将模块中的方法引入到当前类或指定类中作为成员方法。
	 */
	namespace.include = function(object, definition) {
		if (definition == null) {
			definition = object;
			object = currentClass || currentObject;
		} else if (typeof object == STRING) {
			/**
			 * *_*这里有问题,跟API上的说明不符。
			 * 经测试:通过include将Module中定义的方法引入到一个已定义的Class中时,
			 * Module中的方法会成为被引入Class的类函数而不是成员函数,
			 * 所以如果要将模块中的方法引入到类中的话只能通过第一种方式做到。
			 */
			object = currentObject[object];
		}

		addDefinition(currentClass, object, definition);
	};

	// Extends the current Class or, optionally, the given Class Definition with the given
	// Module methods. The methods will be available as Class methods.
	/**
	 * 将模块中的方法引入到当前类或指定类中作为类方法。
	 */
	namespace.extend = function(object, definition) {
		if (definition == null) {
			definition = object;
			object = currentObject;
		} else if (typeof object == STRING) {
			object = currentObject[object];
		}

		addDefinition(null, object, definition);
	};

	// Creates a alias for the given Method, Class, or Module definition.
	/**
	 * 毫无用处的alias方法:(
	 */
	namespace.alias = function(alias, method) {
		var object = currentClass || currentObject;

		object[alias] = object[method];
	};

})();

 最后是我的一点使用经验:

  1. 同一个模块可以被定义多次,这样可以将不同的功能模块放在不同的文件中,但同时又保证它们都处于一个模块的命名空间下,方便模块化管理。同一个类也可以被定义多次,但这种的应用场景不多。
  2. 建议将类成员和类函数定义在extend中,而extend直接写在所属类的定义中。
  3. 后定义的方法总是可以覆盖或增强先定义的方法。
  4. 子类继承父类时,不仅成员函数可以被继承,类函数也是可以的哦!
  5. include方法是有问题的,详见注释。
  6. alias方法就是个大鸡肋:(
0
0
分享到:
评论

相关推荐

    TextClassify2-源码.rar

    《TextClassify2-源码解析与应用》 在当今的信息化时代,自然语言处理(NLP)技术已经成为人工智能领域的重要组成部分。TextClassify2项目是针对文本分类问题的一个开源解决方案,它为我们提供了深入理解文本分类...

    weka 源码解析 classifier类

    ### Weka源码解析:Classifier类详解 #### 一、引言 在机器学习领域,Weka是一款非常流行的开源工具包,它提供了丰富的算法库,适用于数据预处理、分类、回归等多种任务。其中,`Classifier`类是Weka的核心组成...

    Mnist_libsvm_classify_SVM_svmMNIST_MNISTLIBSVM_labelopf_MNIST_源码

    《MNIST数据集上的LibSVM SVM分类与svmMNIST:深入理解与源码解析》 MNIST数据集是机器学习领域中一个经典的图像识别数据集,主要用于手写数字识别。该数据集包含60,000个训练样本和10,000个测试样本,每个样本为28...

    tesseract源码

    **Tesseract OCR 源码解析** Tesseract是一款强大的光学字符识别(OCR)软件,它由HP公司于1985年开发,并在2005年被Google接手后进行了大规模的更新和优化。该软件以其高识别率、开源及跨平台特性而广受开发者欢迎...

    classify:这是4级类别的jquery插件

    本文将详细解析标题为"classify:这是4级类别的jquery插件"的项目,该项目是一个用于实现四级分类的jQuery插件。 首先,让我们了解什么是jQuery插件。jQuery插件是开发者基于jQuery库创建的自定义功能模块,它们可以...

    MATLAB 深度学习简介,matlab深度神经网络,matlab源码.zip

    本文将深入探讨 MATLAB 在深度学习中的应用,包括基本概念、网络架构、模型训练以及源码解析。 深度学习是机器学习的一个分支,它通过模拟人脑神经元的工作机制来实现复杂的数据处理。在 MATLAB 中,深度学习主要...

    一级列表学习源码.rar_列表框_安卓

    5. **Java源码解析**: - ListListActivity.java:这是主Activity的代码,包含ListView的初始化、Adapter的实例化以及数据加载等操作。可能包含点击事件监听,滚动事件处理等功能。 - ClassifyMainAdapter.java和...

    基于matlab的手写数字识别系统源码.zip

    【标题】基于MATLAB的手写数字识别系统源码解析 MATLAB是一款强大的数学计算和数据分析软件,被广泛应用于科学计算、工程设计以及机器学习等领域。本压缩包中的内容是基于MATLAB实现的手写数字识别系统,它利用了...

    weui模板源码

    3. **网页文件解析** - `index.html`:通常作为网站的主页,展示商城的主要功能和推荐商品。 - `mine.html`:可能包含用户个人中心,如账户信息、订单管理、收货地址等。 - `pro_list.html`:产品列表页,用于...

    DeepLearnToolbox-master_SARCNN_神经网络图像_matlab_变化检测_CNN_源码.zip

    《深度学习工具箱:SARCNN神经网络在MATLAB中的图像变化检测CNN源码解析》 在当前的计算机视觉领域,深度学习技术以其强大的模式识别能力,在图像处理和分析方面展现出巨大潜力。本资料包“DeepLearnToolbox-master...

    matlab-通过MATLAB编程实现基于CNN卷积神经网络的手写数字识别算法,数据库为MNIST标准数据库-源码

    5. 源码解析 提供的源码应该包含了上述步骤的实现,可能涉及MATLAB的`deepLearningNetwork`、`trainNetwork`、`classify`等函数。通过阅读源码,我们可以深入理解CNN模型的构建和训练过程,以及如何在MNIST数据集上...

    手势识别matlab源码.rar

    手势识别是计算机视觉领域的一个重要研究方向,它利用摄像头捕捉人体手势,并通过算法解析出手势的含义,从而实现人机交互。在这个名为“手势识别matlab源码”的压缩包中,我们可以推测它包含了一些用于在MATLAB环境...

    基于python的接口测试源码.docx

    #### 三、代码解析 1. **导入必要的库** ```python import requests import json import pandas as pd ``` - `requests`:用于发起HTTP请求。 - `json`:用于处理JSON数据。 - `pandas as pd`:虽然在这...

    MATLAB-LeNet5-master_MATLAB-Lenet5_MATLAB数字识别_CNNMATLAB_matlable

    7. **源码解析**:解压的文件“MATLAB-LeNet5-master_MATLAB-Lenet5_MATLAB数字识别_CNNMATLAB_matlablenet_lenet_源码.zip”包含了实现LeNet-5的MATLAB代码。通过阅读和理解这些代码,我们可以了解每个部分的具体...

    ECGCNN_1DCNNmatlab_1DCNN_matlab1DCNN_matlab神经网络_matlab1DCNN_源码.r

    标题 "ECGCNN_1DCNNmatlab_1DCNN_matlab1DCNN_matlab神经网络_matlab1DCNN_源码.r" 提供的信息暗示,这是一个与使用1维卷积神经网络(1D CNN)处理心电图(ECG)数据相关的MATLAB源代码。在MATLAB中实现1D CNN是一种...

    餐外卖系统小程序模板.zip

    《构建手机端外卖订餐系统:小程序模板解析》 在当今移动互联网时代,外卖订餐已经成为日常生活的一部分。本文将深入探讨“餐外卖系统小程序模板”,一个专为手机端设计的在线外卖叫餐服务模板,旨在帮助开发者快速...

    宏病毒的研究与实例分析03——宏病毒处理篇1

    这将导致Office办公软件在解析VBA工程时,无法找到_macros文件的地址,从而无法执行宏病毒。 宏清除脚本 根据上述原理,我们可以编写一个Python处理脚本来清除宏病毒。该脚本可以读取OLE文件,找到_macros文件的...

Global site tag (gtag.js) - Google Analytics