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