`

Ext.extend用法以及代码解读

阅读更多
概述
Ext.extend是Ext的继承机制,这个函数的代码相当难懂。要明白这个函数的代码,首先要知道这个函数如何使用。
使用方式
使用示例
假设有个function名为SuperClass,要实现一个子类,名为MyClass。下面的两种方式都可以实现这个功能。
MyClass = Ext.extend(SuperClass, { /* */ });
Ext.extend(MyClass, SuperClass, { /* */});

 
下面来个具体示例:
var a = function(id){
    this.id = id;
}
a.prototype = {
    tostring : function(){
        return this.id;
    }
};
            
b = function(id){
    b.superclass.constructor.call(this, id);
}
Ext.extend(b, a, {
    tostring : function(){
        return String.format("b:{0}", this.id);
    }
});
//测试一下
var obj1 = new a("obj1");
alert(obj1.tostring());
var obj2 = new b("obj2");
alert(obj2.tostring());

或者下面的代码,可以得到同样的效果:
var a = function(id){
	this.id = id;
}
a.prototype = {
	tostring : function(){
		return this.id;
	}
};
 
b = Ext.extend(a, {
	tostring : function(){
		return String.format("b:{0}", this.id);
	}
});
//测试一下
var obj1 = new a("obj1");
alert(obj1.tostring());
var obj2 = new b("obj2");
alert(obj2.tostring());
 

一个错误例子
下面看个示例:
BaseClass = function() {
    this.f1 = function() {
        alert("f1 in base");
    }
 
    this.f2 = function() {
        alert("f2 in base");
    }
}
 
ChildClass = function() {
  ChildClass.superclass.constructor.call(this);
}       
 
Ext.extend(ChildClass, BaseClass, {
    f1: function() {
        alert("f1 in child");
    },
 
    f3: function() {
        alert("f3 in child");
    }
});
 
var b = new ChildClass();
b.f1();
b.f2();
b.f3();

 
可以去执行一下,可以发现f1的执行结果仍然是"f1 in base"。并没有真正的达到override的效果。
 
Ext.extend puts the properties specified in the 3rd argument into the subclass's prototype
 
也就是说:第三个参数里面的函数被放置在了子类的prototype中。
而在ChildClass.superclass.constructor.call(this);这句上,BaseClass的f1成了ChildClass的变量,而不是ChildClass.prototype。通过对JavaScript的原型继承的了解,可以知道,实例变量的优先级是高于prototype的,所以上面的这个代码是达不到override的功能的。
 
修改的方式如下:
BaseClass = function() {
};
 
BaseClass.prototype = {
    f1: function() {
        alert("f1 in base");
    }
};

 
代码解读
JavaScript中的继承实现
先了解一下最简单的继承是如何实现的:
function Extend(subFn, superFn){
    subFn.prototype = new superFn()
    subFn.prototype.constructor = subFn
}
 
function Animal(){
    this.say1 = function(){
        alert("Animal");
    }
}
 
function Tiger(){
    this.say2 = function(){
        alert("Tiger");
    }
}
 
Extend(Tiger,Animal);
 
var tiger = new Tiger();
tiger.say1();//"Animal"
tiger.say2();//"Tiger"

 
可以看到最简单的继承只做了两件事情,一是把subFn的prototype设置为superFn的一个实例,然后设置subFn.prototype.constructor为subFn。
 
Ext.extend的代码
Ext.extend函数中用到了Ext.override,这个函数把第二个参数中的所有对象复制到第一个对象的prototype中。首先贴上Ext.override函数的代码:
Ext.override = function(origclass, overrides){
	if(overrides){
		var p = origclass.prototype;
		for(var method in overrides){
			p[method] = overrides[method];
		}
	}
}

 
然后贴上Ext.extend的代码:
 
/**
 * 继承,并由传递的值决定是否覆盖原对象的属性
 * 返回的对象中也增加了override()函数,用于覆盖实例的成员
 * @param {Object} subclass 子类,用于继承(该类继承了父类所有属性,并最终返回该对象)
 * @param {Object} superclass 父类,被继承
 * @param {Object} overrides (该参数可选) 一个对象,将它本身携带的属性对子类进行覆盖
 * @method extend
 */
function extend (){
	// inline overrides
	var io = function(o){
		for(var m in o){
			this[m] = o[m];
		}
	};
	return function(sb, sp, overrides){
		if(typeof sp == 'object'){
			overrides = sp;
			sp = sb;
			sb = function(){sp.apply(this, arguments);};
		}
		var F = function(){}, sbp, spp = sp.prototype;
		F.prototype = spp;
		sbp = sb.prototype = new F();
		sbp.constructor=sb;
		sb.superclass=spp;
		if(spp.constructor == Object.prototype.constructor){
			spp.constructor=sp;
		}
		sb.override = function(o){
			Ext.override(sb, o);
		};
		sbp.override = io;
		Ext.override(sb, overrides);
		return sb;
	};
}();

 
代码中进行了太多的简写,看起来不是特别方便,把代码中的简写补全,代码如下:
function extend(){
    // inline overrides
    var inlineOverride = function(o){
        for (var m in o) {
            this[m] = o[m];
        }
    };
    return function(subFn, superFn, overrides){
        if (typeof superFn == 'object') { 
			//如果subFn也是对象的话(一般来说subFn这里放的是父类的构造函数),那么第三个参数overrides参数相当于被忽略掉
            overrides = superFn;
            superFn = subFn;
			//subFn重新定义了函数 
            subFn = function(){
                superFn.apply(this, arguments);
            };
        }
        var F = function(){
        }, subFnPrototype, superFnPrototype = superFn.prototype;
        F.prototype = superFnPrototype;
        subFnPrototype = subFn.prototype = new F();
		subFnPrototype.constructor = subFn;
		subFn.superclass = superFnPrototype;
        
		if (superFnPrototype.constructor == Object.prototype.constructor) {
            superFnPrototype.constructor = superFn;
        }
        subFn.override = function(obj){
            Ext.override(subFn, obj);
        };
        subFnPrototype.override = inlineOverride;
        Ext.override(subFn, overrides);
        return subFn;
    };
};

 
补全以后也不是特别容易明白,那么我们就把这个代码分开,分为2个参数和3个参数。
 
两个参数的Ext.extend代码
首先把代码改写成两个参数的。
//两个参数的时候的代码,注意第二个参数必须为object
function extend(){
    // inline overrides
    var inlineOverride = function(o){
        for (var m in o) {
            this[m] = o[m];
        }
    };
    return function(superFn, overrides){
		var subFn = function(){
			superFn.apply(this, arguments);
		};
 
        var F = function(){
        }, subFnPrototype, superFnPrototype = superFn.prototype;
		
        F.prototype = superFnPrototype;
		//注意下面两句就是上面最简单的继承实现。
        subFnPrototype = subFn.prototype = new F();
		subFnPrototype.constructor = subFn;
		//添加了superclass属性指向superFn的Prototype
		subFn.superclass = superFnPrototype;
		
		//为subFn和subFnPrototype添加override函数
        subFn.override = function(obj){
            Ext.override(subFn, obj);
        };
        subFnPrototype.override = inlineOverride;
        
		//覆盖掉子类prototype中的属性
        Ext.override(subFn, overrides);
        return subFn;
    };
};

从注释中可以看到,做的工作很简单,只是定义一个subFn函数,这个函数中会调用superFn函数。定义了subFn以后,就使用上面的最简单的继承方式实现继承。然后为subFn和subFn的prototype添加了一个override函数。最后的Ext.override(subFn, overrides);把overrides中的函数写入subFn的prototype中。
 
三个参数的Ext.extend代码
下面我们把函数改写为只处理3个参数的,改写后的代码如下:
//三个参数时的代码
function extend(){
    // inline overrides
    var inlineOverride = function(o){
        for (var m in o) {
            this[m] = o[m];
        }
    };
    return function(subFn, superFn, overrides){
        var F = function(){
        }, subFnPrototype, superFnPrototype = superFn.prototype;
		
        F.prototype = superFnPrototype;
		//注意下面两句就是上面最简单的继承实现。
        subFnPrototype = subFn.prototype = new F();
		subFnPrototype.constructor = subFn;
		//添加了superclass属性指向superFn的Prototype
		subFn.superclass = superFnPrototype;
 
		//为subFn和subFnPrototype添加override函数
        subFn.override = function(obj){
            Ext.override(subFn, obj);
        };
        subFnPrototype.override = inlineOverride;
        
		//覆盖掉子类prototype中的属性
        Ext.override(subFn, overrides);
        return subFn;
    };
};

 
过程与两个参数的时候相差无几,只是两个参数的时候,subFn时重新定义的一个function,而三个参数的时候,这个步骤就省略了。
总结及说明
这样大家就对这个函数很明白了吧,也可以知道Ext.extend的继承只会覆写构造函数prototype中的对象,使用的时候需要多加注意。
 
注意下面一段代码:
if (superFnPrototype.constructor == Object.prototype.constructor) {
	superFnPrototype.constructor = superFn;
}

这段代码我在改写的Ext.extend中省略掉了。原因在于我尝试了多次,发现参数为两个参数的时候,只有第一个参数为Object对象或者为3个参数的时候,第二个参数为Object才会进入此段代码。
分享到:
评论

相关推荐

    Ext.Store的获取方法

    总结来说,在Ext.js中,获取`Ext.Store`应使用`Ext.getStore`方法,而不是`Ext.getCmp`,因为Store是通过`storeId`在内存中注册和管理的,而不是作为页面上的一个可视组件。同时,Store的设计方式有助于数据的安全性...

    jquery.validate.extend.js

    jquery.validate.extend.js

    jquery $.fn.extend

    `$.fn.extend`是jQuery库中的一个核心方法,主要用于扩展jQuery对象的方法集合。这个方法允许开发者自定义jQuery的函数,从而实现对DOM元素的操作或添加新的功能。在jQuery中,`$.fn`实际上是`$.prototype`的一个...

    原生js实现jquery $.extend方法

    原生js实现jquery $.extend方法 通过遍历对象属性来实现

    underscore.extend与$.extend实例比较分析

    在JavaScript开发中,`underscore` 和 `jQuery` 都提供了扩展对象的功能,即 `_.extend()` 和 `$.extend()` 方法。这两个方法允许开发者合并一个或多个对象的属性到目标对象中,实现对象间的属性拷贝。本文将深入...

    Ext.data.Store 读取XML属性值

    `Ext.data.reader.Xml`还支持通过`rootProperty`配置来指定包含所有记录的顶层XML节点,以及通过`successProperty`来确定成功响应的标记。例如,如果XML响应结构如下: ```xml <success>true <!-- item节点......

    Jquery实现$.fn.extend和$.extend函数_.docx

    在JavaScript中,jQuery库提供了两种扩展对象的方法,即`$.fn.extend`和`$.extend`。它们都用于增加或修改现有对象的功能,但应用场景不同。本文将深入解析这两种方法的实现原理和用途。 首先,`$.fn.extend`是用于...

    jQuery.extend和jQuery.fn.extend的区别

    在JavaScript的世界里,jQuery是一个非常流行的库,它简化了DOM操作、事件处理、动画效果以及Ajax交互等任务。在jQuery的API中,`jQuery.extend`和`jQuery.fn.extend`是两个重要的方法,它们用于合并对象属性,但...

    Ext.ux.UploadDialog

    Most configuration options are inherited from Ext.Window (see ExtJs docs). The added ones are: url - the url where to post uploaded files. base_params - additional post params (default to {}). ...

    Ext一些方法的重写

    在JavaScript的世界里,`Ext` 是一个非常知名的库,它为Web开发提供了丰富的组件和工具。...在深入研究`ext-extend.js`文件内容时,你将更全面地了解`Ext`库在实践中的运用,以及如何通过方法重写实现类的灵活定制。

    Ext.js核心函数详解.docx

    4. `Ext.extend( Object subclass, Object superclass, [Object overrides] )`: 这是实现面向对象编程的关键函数,它用于创建子类,将`subclass`扩展自`superclass`。`overrides`参数用于提供子类覆盖父类的方法或...

    Extjs 继承Ext.data.Store不起作用原因分析及解决

    关于这个原因有很多种,我只说下我遇到的 我这样 写Store来复用的 代码如下: DocStore = Ext.extend(Ext.data.Store,{ initComponent:function(){ this.proxy = new Ext.data.HttpProxy({url:this.url}); this....

    ext使用--Panel和iframe联合使用时页面高度的解决方法

    Ext.extend(Ext.layout.container.MyIFrameLayout, Ext.layout.container.Fit, { onLayout: function(ct, target) { var iframe = ct.items.first(); if (iframe && iframe.rendered) { var iframeBody = ...

    Ext.js核心函数详解.pdf

    在JavaScript开发中,Ext.js是一个广泛使用的库,它提供了丰富的UI组件和强大的数据管理功能。在"Ext.js核心函数详解.pdf"中,我们看到了一些关键的Ext.js函数,这些函数对于理解和使用这个框架至关重要。下面是对...

    ext多选下拉列表的全选功能实现

    在ExtJS中,可以使用`addListener`或`on`方法来添加事件监听器。 7. **UI反馈**:在用户进行全选或全取消操作后,界面上应有明显的反馈,例如改变全选按钮的文本或图标状态,以反映当前的选择状态。 8. **优化性能...

    ExtJs 带清空功能的日期组件

    可以通过`Ext.extend()`方法实现这一点。 ```javascript Ext.define('MyApp.form.field.ClearableDate', { extend: 'Ext.form.field.Date', alias: 'widget.clearabledatefield', // 添加其他配置项... }); ``...

    jQuery.extend

    **jQuery.extend** jQuery.extend是jQuery库中的一个非常重要的方法,用于合并两个或更多对象的属性到第一个对象上。这个功能在开发过程中非常...理解其工作原理和各种用法,能帮助我们更有效地编写JavaScript代码。

    Js-$.extend扩展方法使方法参数更灵活.docx

    在提供的代码示例中,`extend`函数接受一个可选参数`arr`,并使用`$.extend()`方法将其与一个预设的对象合并。如果`arr`未定义或为`null`,`$.extend()`会使用空对象`{}`作为源对象,这样就不会改变目标对象的原始...

Global site tag (gtag.js) - Google Analytics