原文链接:http://blog.csdn.net/lovelyelfpop/article/details/50920595
英文原文:What is callParent and callSuper?
Ext JS最好的东西就是它的类系统. 尽管JavaScript没有支持继承的类, ExtJS使用了一些JavaScript方法实现了继承机制. 这使得类可以利用简单的api,通过继承另外的类来实现功能增强、扩展性和代码重用,而这些api在原生JavaScript中并不存在.
我们先来创建一个类 Bar
,它继承 Foo
:
Ext.define('Foo', { someProp : 3, someMethod : function() { console.log('Foo', 'someMethod'); } }); Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4 });
我们看下代码, Foo
定义了成员属性 someProp
和成员函数someMethod
. Bar
继承了 Foo
, 添加了成员属性 anotherProp
,并重写(overwrite)了成员属性 someProp
的值. 这样, Bar
继承了成员函数someMethod
,所以 Bar
的实例可以执行函数 someMethod
. 让我们来实例化并执行一下看看:
var foo = new Foo(); foo.someProp === 3; foo.someMethod(); //输出`Foo someMethod` var bar = new Bar(); bar.anotherProp === 'test'; bar.someProp === 4; bar.someMethod(); //输出'Foo someMethod'
callParent
现在我们要给 Bar的
someMethod
函数添加逻辑,但同时我们还想要执行从 Foo
中继承过来的 someMethod
函数的逻辑. 如果我们只是简单地给 Bar
添加一个 someMethod
函数,比如像这样:
Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4, someMethod : function() { console.log('Bar', 'someMethod'); } });
当我们执行 bar.someMethod();
则只会输出 Bar someMethod
,而不会执行 Foo
类的 someMethod
函数,因为我们覆盖(override)了这个函数. 我们仍然可以使用 callParent
函数调用 Foo
的 someMethod
:
Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4, someMethod : function() { console.log('Bar', 'someMethod'); this.callParent(); } });
现在当 bar.someMethod();
执行的时候, 我们会看到 Bar someMethod
和Foo someMethod
都输出了,因为 this.callParent();
调用了父类 (Foo
) 的 someMethod
函数.
到目前为止, someMethod
函数没有任何参数,所以我们也不必考虑如何把参数传递到父类函数的问题. 我们来修改下 Foo
,接收几个参数:
Ext.define('Foo', { someProp : 3, someMethod : function(callback, scope) { console.log('Foo', 'someMethod'); if (callback) { callback.call(scope || this); } } });
我们修改 someMethod
函数,接收两个可选参数 callback
和 scope
,但是我们需要传递 Bar
类 someMethod
函数的参数,以便 Foo
someMethod
函数可以接收到这些参数并正常运行.
我们有两种方法实现.
第一种是要明确知道有哪些参数,并把这些参数组成一个数组给 callParent
函数去调用. 这个可能需要你自学阅读源码,以便找出父类或者祖先类的函数的参数.
另外一种就是直接用 arguments
关键字,这个关键字就包含了当前函数的所有参数. 下面是两种实现:
Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4, someMethod : function(callback, scope) { console.log('Bar', 'someMethod'); this.callParent([callback, scope]); } });
或者用 arguments
关键字:
Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4, someMethod : function(callback, scope) { console.log('Bar', 'someMethod'); this.callParent(arguments); } });
我个人常用的是第一种方式. 要知道具体的参数,查找文档或源码可能会比较有帮助. 如果你知道有的函数没有参数, 比如 Ext.Component
的 initComponent
函数, 那么你就可以直接执行 callParent
而不需要传递参数: this.callParent();
callSuper
就像callParent
, 当你重写(overwrite)某个类的时候,使用 callSuper
就可以调用被重写类的父类的函数. 它们有2个区别:
callSuper
只用在覆盖(override)继承中(override也属于继承)
callParent
调用被继承过来的父类的函数, 而 callSuper
会跳过被覆盖继承的类,而调用再上一层的类的函数.
我们来覆盖(override)继承 Bar
,探讨下 callSuper
函数的作用:
Ext.define('Override.Bar', { override : 'Bar', someMethod : function(callback, scope) { console.log('Override.Bar', 'someMethod'); } });
这个例子中, 我们重写(overwrite)了 Bar
类的 someMethod
函数. 当执行 bar.someMethod();
时,我们只会看到 Override.Bar someMethod
输出. 我们要做的不是调用 Bar
类的 someMethod
函数,而是跳过 Bar
类,去调用 Foo
类的. 可以通过 callSuper
来实现:
Ext.define('Override.Bar', { override : 'Bar', someMethod : function(callback, scope) { console.log('Override.Bar', 'someMethod'); this.callSuper([callback, scope]); } });
现在执行 bar.someMethod();
, 我们就看到了 Override.Bar someMethod
和 Foo someMethod
都被输出了. 还有 callSuper
传递参数的方式和 callParent
是一样的.
如果 Foo
类的 someMethod
函数有返回值呢? 我们怎么在 callParent
和 callSuper
中处理返回值?其实很简单. 先来看看对 Foo
的改动:
Ext.define('Foo', { someProp : 3, someMethod : function(callback, scope) { console.log('Foo', 'someMethod'); if (callback) { callback.call(scope || this); } return this; } });
现在 someMethod
是链式的,因为他返回了 this
,这个 this
应该是 Foo
类. 现在我们需要处理 Bar
类的 callParent
:
Ext.define('Bar', { extend : 'Foo', anotherProp : 'test', someProp : 4, someMethod : function(callback, scope) { console.log('Bar', 'someMethod'); return this.callParent([callback, scope]); } });
我做的只是加了个 return
, callParent
仅仅只是一个调用父类函数的占位符,所以父类函数返回什么, callParent
就返回什么. 同理, callSuper
也是这样:
Ext.define('Override.Bar', { override : 'Bar', someMethod : function(callback, scope) { console.log('Override.Bar', 'someMethod'); return this.callSuper([callback, scope]); } });
如果你想使用 callParent
或 callSuper
的返回值呢? 把返回值用变量存起来就行了. 再说一次,callParent
和 callSuper
都一样的,所以我只写一个例子:
Ext.define('Override.Bar', { override : 'Bar', someMethod : function(callback, scope) { console.log('Override.Bar', 'someMethod'); var ret = this.callSuper([callback, scope]); console.log('Override.Bar', ret.someProp); return ret; } });
当执行 bar.someMethod();
的时候,会返回 this
(Bar类的实例) ,但是会有如下顺序的输出: Override.Bar someMethod
, Foo someMethod
和 Override.Bar 4
. 有几个问题要注意, 因为我们在覆盖(override)继承中用的是 callSuper
, 所以 Bar
类中的 someMethod
函数并不会执行,而是被 callSuper
给跳过了,然后函数作用域是 Bar
类的实例(因为上面用的是 var bar = new Bar();
) ,这就是为什么 ret.someProp
是 4
而不是 3
.
欢迎加入Sencha Touch + Phonegap交流群
1群:194182999 (满)
2群:419834979
共同学习交流(博主QQ:479858761)