[Sencha ExtJS & Touch] 什么是 callParent 和 callSuper ?

原文链接: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]);
    }
});

我做的只是加了个 returncallParent 仅仅只是一个调用父类函数的占位符,所以父类函数返回什么, 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 someMethodFoo 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)

你可能感兴趣的:(html5,ExtJs,Web应用,sencha)