如何使用回调函数在 TypeScript 中保留词法范围 [英] How can I preserve lexical scope in TypeScript with a callback function

查看:31
本文介绍了如何使用回调函数在 TypeScript 中保留词法范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 TypeScript 类,有一个我打算用作回调的函数:

I have a TypeScript class, with a function that I intend to use as a callback:

removeRow(_this:MyClass): void {
    ...
    // 'this' is now the window object
    // I must use '_this' to get the class itself
    ...
}

我将它传递给另一个函数

I pass it in to another function

this.deleteRow(this.removeRow);

它依次调用一个 jQuery Ajax 方法,如果成功,它会像这样调用回调:

which in turn calls a jQuery Ajax method, which if successful, invokes the callback like this:

deleteItem(removeRowCallback: (_this:MyClass) => void ): void {
    $.ajax(action, {
        data: { "id": id },
        type: "POST"
    })
    .done(() => {
        removeRowCallback(this);
    })
    .fail(() => {
        alert("There was an error!");
    });
}

我可以保留对我的类的this"引用的唯一方法是将其传递给回调,如上所示.它有效,但它是裤子代码.如果我没有像这样连接this"(抱歉),那么回调方法中对 this 的任何引用都已恢复到 Window 对象.因为我一直在使用箭头函数,所以我预计this"将是类本身,因为它在我的类中的其他地方.

The only way I can preserve the 'this' reference to my class is to pass it on to the callback, as demonstrated above. It works, but it's pants code. If I don't wire up the 'this' like this (sorry), then any reference to this in the callback method has reverted to the Window object. Because I'm using arrow functions all the way, I expected that the 'this' would be the class itself, as it is elsewhere in my class.

有人知道如何在 TypeScript 中传递回调,从而保留词法作用域吗?

Anyone know how to pass callbacks around in TypeScript, preserving lexical scope?

推荐答案

Edit 2014-01-28:

新读者,请务必查看下面扎克的回答.

他有一个更简洁的解决方案,可以让您使用粗箭头语法在类定义中定义和实例化作用域函数.

He has a much neater solution that will let you define and instantiate a scoped function in the class definition using the fat arrow syntax.

我唯一要补充的是,关于 Zac 回答中的选项 5,可以使用以下语法指定方法签名和返回类型而无需任何重复:

The only thing I will add is that, in regard to option 5 in Zac's answer, it's possible to specify the method signature and return type without any repetition using this syntax:

public myMethod = (prop1: number): string => {
    return 'asdf';
}

编辑 2013-05-28:

定义函数属性类型的语法已更改(自 TypeScript 0.8 版起).

Edit 2013-05-28:

The syntax for defining a function property type has changed (since TypeScript version 0.8).

以前你会像这样定义一个函数类型:

Previously you would define a function type like this:

class Test {
   removeRow: (): void;
}

现在改为:

class Test {
   removeRow: () => void;
}

我在下面更新了我的答案以包含此新更改.

I have updated my answer below to include this new change.

另外:如果您需要为同一个函数名定义多个函数签名(例如运行时函数重载),那么您可以使用对象映射表示法(这在 jQuery 中广泛使用)描述符文件):

As a further aside: If you need to define multiple function signatures for the same function name (e.g. runtime function overloading) then you can use the object map notation (this is used extensively in the jQuery descriptor file):

class Test {
    removeRow: {
        (): void;
        (param: string): string;
    };
}

<小时>

您需要将 removeRow() 的签名定义为类的属性,但在构造函数中分配实现.


You need to define the signature for removeRow() as a property on your class but assign the implementation in the constructor.

有几种不同的方法可以做到这一点.

There are a few different ways you can do this.

class Test {

    // Define the method signature here.
    removeRow: () => void;

    constructor (){
        // Implement the method using the fat arrow syntax.
        this.removeRow = () => {
            // Perform your logic to remove the row.
            // Reference `this` as needed.
        }
    }

}

如果你想让你的构造函数最小化,那么你可以在类定义中保留 removeRow 方法,并在构造函数中分配一个代理函数:

If you want to keep your constructor minimal then you can just keep the removeRow method in the class definition and just assign a proxy function in the constructor:

class Test {

    // Again, define the method signature here.
    removeRowProxy: () => void;

    constructor (){
        // Assign the method implementation here.
        this.removeRowProxy = () => {
            this.removeRow.apply(this, arguments);
        }
    }

    removeRow(): void {
        // ... removeRow logic here.
    }

}

选项 3

最后,如果您使用像 underscore 或 jQuery 这样的库,那么您可以使用它们的实用方法来创建代理:

Option 3

And finally, if you're using a library like underscore or jQuery then you can just use their utility method to create the proxy:

class Test {

    // Define the method signature here.
    removeRowProxy: () => void;

    constructor (){
        // Use jQuery to bind removeRow to this instance.
        this.removeRowProxy = $.proxy(this.removeRow, this);
    }

    removeRow(): void {
        // ... removeRow logic here.
    }

}

<小时>

然后你可以稍微整理一下你的 deleteItem 方法:

// Specify `Function` as the callback type.
// NOTE: You can define a specific signature if needed.
deleteItem(removeRowCallback: Function ): void {
    $.ajax(action, {
        data: { "id": id },
        type: "POST"
    })

    // Pass the callback here.
    // 
    // You don't need the fat arrow syntax here
    // because the callback has already been bound
    // to the correct scope.
    .done(removeRowCallback)

    .fail(() => {
        alert("There was an error!");
    });
}

这篇关于如何使用回调函数在 TypeScript 中保留词法范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆