Extjs4 源码分析系列一 类的创建过程
2015-02-27 15:35
447 查看
Extjs源码分析
第一次写博客,以下是我个人阅读了Extjs的源码,借鉴了Extjs权威指南这本书的部分内容,和自己的一些调试,写出了我自己对Extjs的架构和源码级别的一些理解和认知.写的不好的地方,还请各位看官多多包涵,提出宝贵意见.本文省略了源码中的一些调试语句,只针对关键部分进行讲解.
从Ext的四个基础的classs开始,先看src/class/目录下面的四个js文件:Base.js,Class.js,ClassManager.js,Loader.js.
Base.js中定义了 Base = function(){},也就是说Base是一个function,然后又调用Ext.apply(Base, {}),给function Base 添加了一些属性和方法,可以说Base是所有类的基类.ClassManager.js这个js文件是管理Ext的类系统的,Class.js是用来生成类的,Loader.js是用来动态加载js文件的.
我们先从这里开始分析,一般在Extjs中,我们常常这样定义一个类Ext.define('AAA',{}),Ext.define这个方法在ClassManager.js文件中.
define: function (className, data, createdFn) { //调用Manager的静态方法create return Manager.create.apply(Manager, arguments); },
这里又调用了Manager 的create方法,第一个参数为class的名字,第二个 参数为传入的配置对象,第三个参数为创建了class后的回调函数.
create: function(className, data, createdFn) { //ctor指向一个function constructor var ctor = makeCtor(); if (typeof data == 'function') { data = data(ctor); } data.$className = className; //调用 Class.js文件的 Class的构造方法 //第三个参数是onCreated return new Class(ctor, data, function() {.....}); }
值得注意的是makeCtor这个方法.
function makeCtor () { function constructor () { return this.constructor.apply(this, arguments) || null; } return constructor; }
这里是一个闭包,返回了 function constructor,这里的用途是在实例化class的时候执行Class的构造方法用的,
更详细的我会在Ext.create方法的源码解读时来分析.接下来给data,也就是传入的配置项添加了一个属性$className,保存类名,接下来new Class(ctor, data, function() {.......}) ;Class这个类的源代码在Class.js中,我们暂时先不去管最后一个参数,也就是那个回调函数,这个在类创建的最后一步才会体现出他的作用.
Class.js中定义了 Ext.Class = ExtClass = function(Class, data, onCreated) {...},之后又Ext.执行了apply(ExtClass, {}),给ExtClass这个function添加了一些静态方法,包括了后面需要调用的create方法.下面我们来看一下 ExtClass中又做了些什么?
Ext.Class = ExtClass = function(Class, data, onCreated) { //这是用来调整参数位置的,new Class(ctor, data, function() {},如果ctor不是function 需要调整参数,这里 不去关注 if (typeof Class != 'function') { onCreated = data; data = Class; Class = null; } if (!data) { data = {}; } //调用Class的静态方法create Class = ExtClass.create(Class, data); //执行Class的处理器 ExtClass.process(Class, data, onCreated); return Class; };
这里看到了执行了ExtClass的create方法和process方法.先来看create方法,这里很简单,就是把Ext.Base这个类的静态方法和属性全都复制到传入的class中,这个class实际上就是makeCtor()这个方法返回的function constructor,源代码如下:
create: function(Class, data) { var name, i; if (!Class) { Class = makeCtor( //<debug> data.$className //</debug> ); } //拷贝Ext.Base类的静态方法到子类Class上 for (i = 0; i < baseStaticMemberLength; i++) { name = baseStaticMembers[i]; Class[name] = Base[name]; } return Class; }
接下来比较重要的是process方法,这个方法比较长,乍看比较复杂,其实仔细看看也很容易理解.
先贴上源代码:
process: function(Class, data, onCreated) { //ext 预制的几个处理器 ,有三个必须执行的是 className ,loader,extend /** * defaultPreprocessors: 0: "className" 1: "loader" 2: "extend" 3: "statics" 4: "inheritableStatics" 5: "config" 6: "mixins" 7: "alias" length: 8 registeredPreprocessors: registeredPreprocessors: Object alias: Object fn: function (cls, data) { name: "alias" properties: Array[2] __proto__: Object className: Object fn: function (cls, data) { name: "className" properties: true __proto__: Object config: Object fn: function (Class, data) { name: "config" properties: Array[1] __proto__: Object extend: Object fn: function (Class, data, hooks) { name: "extend" properties: true __proto__: Object inheritableStatics: Object fn: function (Class, data) { name: "inheritableStatics" properties: Array[1] __proto__: Object loader: Object fn: function (cls, data, hooks, continueFn) { name: "loader" properties: true __proto__: Object mixins: Object fn: function (Class, data, hooks) { name: "mixins" properties: Array[1] __proto__: Object statics: Object fn: function (Class, data) { name: "statics" properties: Array[1] __proto__: Object */ var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors, registeredPreprocessors = this.preprocessors, hooks = { onBeforeCreated: this.onBeforeCreated }, preprocessors = [], preprocessor, preprocessorsProperties, i, ln, j, subLn, preprocessorProperty; delete data.preprocessors; for (i = 0,ln = preprocessorStack.length; i < ln; i++) { preprocessor = preprocessorStack[i]; if (typeof preprocessor == 'string') { preprocessor = registeredPreprocessors[preprocessor]; preprocessorsProperties = preprocessor.properties; if (preprocessorsProperties === true) { preprocessors.push(preprocessor.fn); } //如果preprocessorsProperties 不是true,是数组的话 else if (preprocessorsProperties) { for (j = 0,subLn = preprocessorsProperties.length; j < subLn; j++) { preprocessorProperty = preprocessorsProperties[j]; //并且在data中配置了该处理器的key,如inheritableStatics if (data.hasOwnProperty(preprocessorProperty)) { preprocessors.push(preprocessor.fn); break; } } } } else { preprocessors.push(preprocessor); } } //onCreated是ClassManger.js中 create 方法 return new Class(ctor, data, function() )的第三个参数 hooks.onCreated = onCreated ? onCreated : Ext.emptyFn; hooks.preprocessors = preprocessors; //执行处理器 this.doProcess(Class, data, hooks); }
首先判断配置项中是否配置了preprocessors属性,如果没有的话采用默认的预处理器栈
,
这是一个数组['className','loader','extend','statics','inheritableStatics','config','mixins','alias'],registerPreprocessors的值通过debug可以看到如下图
registeredPreprocessors: Object
alias: Object
fn: function (cls, data) {
name: "alias"
properties: Array[2]
__proto__: Object
className: Object
fn: function (cls, data) {
name: "className"
properties: true
__proto__: Object
config: Object
fn: function (Class, data) {
name: "config"
properties: Array[1]
__proto__: Object
extend: Object
fn: function (Class, data, hooks) {
name: "extend"
properties: true
__proto__: Object
inheritableStatics: Object
fn: function (Class, data) {
name: "inheritableStatics"
properties: Array[1]
__proto__: Object
loader: Object
fn: function (cls, data, hooks, continueFn) {
name: "loader"
properties: true
__proto__: Object
mixins: Object
fn: function (Class, data, hooks) {
name: "mixins"
properties: Array[1]
__proto__: Object
statics: Object
fn: function (Class, data) {
name: "statics"
properties: Array[1]
__proto__: Object
这是具体的值.
接下来就是循环 preprocessor数组,在根据数组的值作为key,在registerProprocessor中找到,然后判断处理器的properties的值是否为true,如果为true,是一定要先执行的处理器,默认有三个预处理器:className,loader,extend,如果preprocessorsProperties 不是true,是数组的话,那么久需要判断出入的配置项是否配置了该处理器的配置,如果配置了的话,也需要push到preprocessors数组中,最后添加到hooks对象上,调用this.doProcess(Class, data, hooks),注意这里的this指向的是function ExtClass,也就是调用ExtClass的静态方法doProcess.
下面在看doProcess的源代码:
doProcess: function(Class, data, hooks) { var me = this, preprocessors = hooks.preprocessors, preprocessor = preprocessors.shift(), doProcess = me.doProcess; for ( ; preprocessor ; preprocessor = preprocessors.shift()) { // Returning false signifies an asynchronous preprocessor - it will call doProcess when we can continue if (preprocessor.call(me, Class, data, hooks, doProcess) === false) { return; } } //执行Ext.Class的静态方法 onBeforeCreated hooks.onBeforeCreated.apply(me, arguments); },
从hooks.preprocessors 数组中依次弹出处理器,并调用处理器的方法,传入ExtClass,Class,data配置,hooks,和doProcess方法,如果执行处理器的执行结果为false,就返回,不在执行后面的处理器,class初始化失败.最后执行hooks.onBeforeCreated方法,这个就是之前我们说的new Class(ctor, data, function() {.......}) ,执行第三个参数,即回调函数.
本文先讲到这里,接下来就是分析这些类的预处理器究竟做了哪些事情,放到第二篇在继续.
相关文章推荐
- Extjs4 源码分析系列一 类的创建过程
- redis客户端Jedis源码分析系列——连接池的创建过程
- lucene4.5源码分析系列:索引的创建过程
- openfire vcard的创建,更新过程源码分析
- 【Mybatis源码分析】01-SqlSessionFactory的创建过程
- linux内核中socket的创建过程源码分析(总结性质)
- linux内核中socket的创建过程源码分析(详细分析)
- lucene4.5源码分析系列:搜索过程
- OpenStack 创建快照(Create Snapshot)过程源码分析
- Qemu-KVM虚拟机初始化及创建过程源码简要分析(一)
- linux内核中socket的创建过程源码分析(总结性质)
- hsqldb源码分析系列3 执行引擎分析 插入过程分析
- nova创建虚拟机源码分析系列之五 nova源码分发实现
- nova创建虚拟机源码分析系列之七 传入参数转换成内部id
- linux内核中socket的创建过程源码分析(详细分析)
- hsqldb源码分析系列3 执行引擎分析 插入过程分析
- mina3源码分析,回话过程创建(二)
- PDF阅读器系列之--MuPDF源码分析过程(一)
- Android源码分析之SystemServer的创建过程
- Spring原理与源码分析系列(二)- Spring IoC容器启动过程分析(上)