打字稿和淘汰赛结合“这”问题 - 拉姆达功能所需要的?(TypeScript and Knockou

2019-07-03 15:24发布

我一直在使用的打字稿及KnockoutJS编辑电子邮件列表创建的HtmlHelper功能。

邮件列表是淘汰赛ObservableArray称为电子邮件 ,和我对每一个项目的链接删除它们。 这是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>

删除链接绑定到$ parent.deleteItem这是在视图模型的方法:

// remove item
public deleteItem(emailToDelete: string) {
    // remove item from list
    this.emails.remove(emailToDelete);
}

这一切工作,直到执行deleteItem方法。 的“本”在该方法中,当它被称为是在阵列中的项目,而不是视图模型。 因此this.emails为空引用和失败。

我知道,打字稿支持lambda语法,但我找不到写这个(有几个例子在那里),以正确的方式。

还是有不同的方法,我可以走?

Answer 1:

您可以通过声明方法体类构造函数中获得“这个”正确关闭

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

更新:

看来,因为打字稿版本0.9.1您可以通过使用拉姆达字段初始达到相同的结果:

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


Answer 2:

手套的人! 只要绑定$父就象这样:

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


Answer 3:

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

您可能需要为填充工具Function.bind()

// Polyfill for Function.bind(). Slightly modified version of
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
if (typeof Function.prototype.bind !== "function") {
    Function.prototype.bind = function(oThis) {
        if (typeof this !== "function") {
            // closest thing possible to the ECMAScript 5 internal IsCallable function
            throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
        }

        var aArgs = <any[]> Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function() {},
            fBound = function() {
                return fToBind.apply(this instanceof fNOP && oThis ? this: oThis, aArgs.concat());
            };

        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();

        return fBound;
    };
}


Answer 4:

我的最终解决方案是一个基类,即重新绑定所有的原型功能本身的构造。 就像马库斯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创建一个小的代理功能。
  • 通过不把功能上构造的类代码更好的组织。
  • 任何功能可以作为一个回调,则无需修改代码时,函数从一个事件被调用。
  • 你不必绑定功能两倍的风险。
  • 这是更好的功能绑定只有一次,每次执行点击/事件绑定时间,而不是做在视图中。

PS:
你仍然需要绑定填充工具。
我使用typesript 0.9.5



Answer 5:

加入我的2美分,也有一个肮脏的方式,它利用由打字稿编译器创建,以保持这一参考变量_this:

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


Answer 6:

我被灵感bind的答案,这个来了,我认为这一点更易于阅读。

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

裹在一个lambda /匿名函数的方法。 不要忘了()。



Answer 7:

使用数据绑定是这样的:

data-bind="click:$parent.deleteItem.bind($parent)"

分配thisthat ,如下图所示

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


Answer 8:

虽然我更喜欢Markus的解决方案,这是我必须解决这个问题之前使用:

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

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

需要注意的是额外的参数可以传递给方法,通过该方法的名称后添加他们:

fixThis($parent, 'deleteItem', arg1, arg2);


文章来源: TypeScript and Knockout binding to 'this' issue - lambda function needed?