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

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

问题描述

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

  removeRow(_this:MyClass ):void {
...
//'this'现在是窗口对象
//我必须使用'_this'来获取类本身
...
}

我将其传递给另一个函数

  this.deleteRow(this.removeRow); 

这会调用一个jQuery Ajax方法,如果成功,调用回调, p>

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

我可以保留对我的类的'this'引用的唯一方法是传递给回调,如上所示。它工作,但它的裤子代码。如果我不像这样(遗憾)连接'this',那么在回调方法中对此的任何引用都已还原到Window对象。因为我一直使用箭头函数,我预计'this'将是类本身,因为它在我的类中的其他地方。



任何人都知道

解决方案

编辑2014-01-28:



新读者请务必查看以下的Zac答案



他有一个更简洁的解决方案,它将允许你使用胖箭头语法在类定义中定义和实例化一个作用域的函数。



我要补充的唯一的事情是,关于选项5 在Zac的答案,可以指定方法签名和返回类型没有任何重复使用这种语法:

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



编辑2013-05-28:



定义函数属性类型的语法已更改(自TypeScript版本0.8开始)。



以前,您将定义一个函数类型,如下所示: p>

  class Test {
removeRow:():void;
}

现在更改为:

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

我已经更新了下面的答案,

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

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






您需要定义

作为您类的属性的 removeRow几种不同的方式可以做到这一点。



选项1



 测试{

//在这里定义方法签名。
removeRow:()=> void;

constructor(){
//使用胖箭头语法实现该方法。
this.removeRow =()=> {
//执行您的逻辑删除行。
//根据需要引用`this`。
}
}

}

想要保持你的构造函数最小,那么你可以只保留 removeRow 方法在类定义,只需在构造函数中分配一个代理函数:



选项2



  class Test {

//再次定义方法签名。
removeRowProxy:()=> void;

constructor(){
//在此处分配方法实现。
this.removeRowProxy =()=> {
this.removeRow.apply(this,arguments);
}
}

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

}



选项3



最后,如果你使用下划线或jQuery这样的库,你可以使用它们的实用方法创建代理:

  class Test {

//在这里定义方法签名。
removeRowProxy:()=> void;

constructor(){
//使用jQuery将removeRow绑定到此实例。
this.removeRowProxy = $ .proxy(this.removeRow,this);
}

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

}





$ b b

然后,您可以稍微整理 deleteItem 方法:

  //指定Function作为回调类型。 
//注意:如果需要,您可以定义特定签名。
deleteItem(removeRowCallback:Function):void {
$ .ajax(action,{
data:{id:id},
type:POST
})

//在这里传递回调函数。
//
//这里不需要fat arrow语法
//因为回调已经绑定了
//到正确的范围。
.done(removeRowCallback)

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


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);

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!");
    });
}

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.

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

解决方案

Edit 2014-01-28:

New readers, make sure you check out Zac's answer below.

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.

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';
}

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;
}

This has now changed to:

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

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

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;
    };
}


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.

Option 1

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.
        }
    }

}

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:

Option 2

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.
    }

}

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.
    }

}


Then you can tidy up your deleteItem method a bit:

// 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天全站免登陆