打字脚本和敲除绑定到';这';问题-需要lambda函数吗?

打字脚本和敲除绑定到';这';问题-需要lambda函数吗?,lambda,knockout.js,typescript,Lambda,Knockout.js,Typescript,我一直在使用TypeScript和KnockoutJS创建一个htmlHelper函数来编辑电子邮件列表 电子邮件列表是一个名为“电子邮件”的淘汰列表,我有一个针对每个项目的链接来删除它们。这是HTML片段: <ul data-bind="foreach: emails" > <li> <a href="#" data-bind="click: $parent.deleteItem">Delete</a> &

我一直在使用TypeScript和KnockoutJS创建一个htmlHelper函数来编辑电子邮件列表

电子邮件列表是一个名为“电子邮件”的淘汰列表,我有一个针对每个项目的链接来删除它们。这是HTML片段:

<ul data-bind="foreach: emails" >
    <li>
        <a href="#" data-bind="click: $parent.deleteItem">Delete</a>
        &nbsp;<span data-bind="text: $data"></span>
    </li>
</ul>
在执行deleteItem方法之前,所有这些都有效。调用此方法时,该方法中的“this”是数组中的项,而不是视图模型。因此,this.emails是一个空引用并且失败

我知道TypeScript支持Lambda语法,但我找不到正确的方法来编写它(没有几个例子)


或者我可以采取另一种方法吗?

您可以通过在类构造函数中声明方法体来获得“this”的正确闭包

declare class Email { }
declare class ObservableArray {
    remove(any): void;
}

class MyViewModel {
    public emails : ObservableArray;

    constructor() {
        Rebind(this);
    }

    public deleteItem(emailToDelete: Email) {
        this.emails.remove(emailToDelete);
    }
}

function Rebind(obj : any)
{
    var prototype = <Object>obj.constructor.prototype;
    for (var name in prototype) {
        if (!obj.hasOwnProperty(name)
                && typeof prototype[name] === "function") {
            var method = <Function>prototype[name];
            obj[name] = method.bind(obj);
        }
    }
}
class VM {
    public deleteItem: (emailToDelete: string) => void;

    constructor() {
        this.deleteItem = (emailToDelete: string) => {
            // 'this' will be pointing to 'this' from constructor
            // no matter from where this method will be called
            this.emails.remove(emailToDelete);
        }
    }        
}
更新:

似乎由于Typescript版本0.9.1,您可以通过使用lambda字段初始值设定项来实现相同的结果:

class VM {
    public deleteItem = (emailToDelete: string) => {
        this.emails.remove(emailToDelete);
    }        
}

虽然我更喜欢马库斯的解决方案,但以下是我以前用来解决这个问题的方法:

public fixThis(_this, func) {
    return function () {
        return _this[func].apply(_this, arguments);
    };
}

<a href="#" data-bind="click: fixThis($parent, 'deleteItem')">Delete</a>

戴手套的人!只需绑定$parent,如下所示:

<a href="#" data-bind="click: $parent.deleteItem.bind($parent)">Delete</a>

我受到了
bind
答案的启发,想出了这个,我认为它更容易阅读


将该方法包装在lambda/匿名函数中。不要忘记()。

我的最终解决方案是一个基类,它将所有原型函数重新绑定到构造函数上的自身。很像Markus Jarderot的解决方案

class BaseClass {
    constructor() {
        for (var i in this) {
            if (!this.hasOwnProperty(i) && typeof (this[i]) === 'function' && i != 'constructor') {
                this[i] = this[i].bind(this);
            }
        }
    }
}
优点:

  • 所有子类都必须调用超级构造函数,这是我想要的行为
  • 执行重新绑定代码时,对象中只有原型函数(稍后添加变量)
  • 它避免了在每个对象上创建大函数。调用bind时,每个对象只创建一个小的代理函数
  • 通过不将函数放在构造函数上,更好地组织类代码
  • 任何函数都可以用作回调函数,从事件调用函数时不需要更改代码
  • 您没有绑定函数两次的风险
  • 最好只绑定一次函数,而不是每次执行单击/事件绑定时都在视图中进行绑定
附言:
您仍然需要绑定polyfill。

我正在使用typesript 0.9.5来添加我的2美分,还有一种肮脏的方式,它利用Typescript编译器创建的变量this来保留对它的引用:

public deleteItem(emailToDelete: string) {
    var that = eval('_this');
    // remove item from list
    that.emails.remove(emailToDelete); // remove? in JS,  really? 
}

使用数据绑定,如下所示:

data-bind="click:$parent.deleteItem.bind($parent)"
这个
分配给
那个
,如下所示

public deleteItem(itemToDelete) 
{
    var that = this;
    // remove item from list
    that.emails.remove(itemToDelete); 
}

我没有使用TypeScript,但是Javascript中通常的解决方案是将viewmodel实例引用保存到一个变量,例如
var self=this
,然后使用它引用
emails
对象,例如
self.emails.remove(emailToDelete)
。也许您知道ts语法可以做到这一点。后续问题:谢谢您:只有此方法需要此修复,因为所有其他方法似乎都正常工作。请注意,您还必须编写
this.deleteItem=(emailToDelete:string)=>{…}
。您不能使用
this.deleteItem=function(emailToDelete:string){…}
语法,因为
this
在这里表示内部函数的上下文。请注意,这不会创建“prototype.function”。这不是一场好的演出-perspective@Richard这只会真正成为一个问题,如果OP将有数百个该对象的实例,可能永远不会有超过一个单一的视图模型,所以它不应该成为一个问题。永远不要担心性能,直到你不得不担心性能:)这一个对meWow来说很好。。谢谢相当复杂的解决方案!我假设这是您一般用来解决此问题的方法?当调用构造函数时,它将所有方法绑定到实例。您可能需要一个polyfill for bind(对于IE8)优秀的解决方案。谢谢分享!
public deleteItem(emailToDelete: string) {
    var that = eval('_this');
    // remove item from list
    that.emails.remove(emailToDelete); // remove? in JS,  really? 
}
data-bind="click:$parent.deleteItem.bind($parent)"
public deleteItem(itemToDelete) 
{
    var that = this;
    // remove item from list
    that.emails.remove(itemToDelete); 
}