【问题标题】:TypeScript: How to use both fat arrow and this?TypeScript:如何同时使用胖箭头和这个?
【发布时间】:2015-11-08 14:40:52
【问题描述】:

我正在使用非常有用的本地胖箭头在回调中保留this 上下文。但是,有时我需要访问 this 的值,如果我没有使用粗箭头的话。

一个示例是事件回调,其中this 具有事件发生的元素的值(我知道在这个特定示例中您可以使用event.currentTarget,但假设您不能使用举个例子):

function callback() {
    // How to access the button that was clicked?
}

$('.button').click(() => { callback() });

注意:我遇到过this question,它处理了同样的问题,但在 CoffeeScript 中。

【问题讨论】:

  • 使用普通函数,并将外部this存储在变量中。
  • 无论this 绑定如何,不要忘记event.currentTarget 获取事件目标的好方法(请注意,它将是HTMLElement,而不是jQuery 对象)。跨度>

标签: javascript typescript


【解决方案1】:

@poke 的回答是正确的想法,但有几个问题:

function thisAsThat (callback) {
    return function () {
        return callback.apply(null, [this].concat(arguments));
    }
}

首先,arguments 不是一个真正的数组,所以如上所示调用concat() 会产生一个嵌套数组:

[0] = this
[1] = [ [0] = param1, [1] = param2, ... ]

要解决这个问题,use slice()arguments 转换为真正的数组:

        return callback.apply(null, [this].concat(Array.prototype.slice.call(arguments)));

结果:

[0] = this
[1] = param1
[2] = param2
...

其次,将null 作为第一个参数传递给 apply() 对我不起作用;我必须明确地通过类 Foo 的this。这是一个完整的例子:

class Foo {

    public setClickHandler(checkbox: JQuery): void {
        checkbox.click(this.captureThis(this.onCheckboxClick));
    }

    protected onCheckboxClick(checkbox: HTMLInputElement, event: Event) {
        // 'this' refers to class Foo
    }

    protected captureThis(callback) {
        var self = this;
        return function () {
            return callback.apply(self, [this].concat(Array.prototype.slice.call(arguments)));
        }
    }

}

使用这种方法,onCheckboxClick() 回调可以访问 this 类和在典型的 click 事件回调中本来是 this 的复选框元素(作为第一个参数)。使用 captureThis() 的缺点是你失去了 TypeScript 的回调类型安全性,因此 Typescript 无法阻止你搞乱回调函数签名。

【讨论】:

  • 似乎在实现中发生了一些变化,因为我记得 [this].concat(...) 方法在过去有效。另外,我假设将null 作为第一个参数传递对您不起作用,因为您的方法完全替换了粗箭头函数(因为您基本上是在复制它们的功能)。如果你使用粗箭头函数,你可以保持它的类型安全。
  • 但是你不能使用粗箭头,因为它会在[this].concat(...) 中重写this 来引用类Foo 而不是复选框。
【解决方案2】:

您可以编写一个装饰器函数,将胖箭头函数包装在另一个函数中,该函数允许访问通常的this,并将该值作为附加参数传递给胖箭头函数:

function thisAsThat (callback) {
    return function () {
        return callback.apply(null, [this].concat(arguments));
    }
}

因此,当您使用胖箭头函数调用 thisAsThat 时,这基本上会返回一个不同的回调函数,该函数在调用时会使用所有参数调用胖箭头函数,但会在前面添加 this 作为参数.由于您无法绑定胖箭头函数,因此您只需调用bindapply 就可以了,而不必担心失去价值。

然后你可以像这样使用它:

element.addEventListener('click', thisAsThat((that, evt) => console.log(this, that, evt)));

这将记录当前作用域的this(根据胖箭头规则),回调函数的thisthat(指向事件处理程序的元素),以及事件本身(但基本上,所有参数仍然会传递)。

【讨论】:

  • 谢谢 - 这是一个简单而聪明的想法。不过有一个问题——.bind 真的需要吗?我可以(如我所见)单独使用.apply 实现相同的效果,如下所示:function thisAsThat(callback) { return function() { return callback.apply(null, [this].concat(arguments)); }; }。您认为这种方法有什么问题吗?
  • 是的,应该也可以。我只使用了bind,所以我不必玩arguments(因为它不是一个数组,而只是“类数组”)。但是,是的,像这样使用concat 似乎是个好主意。我会调整我的答案以使用它:)
【解决方案3】:

您不需要为此使用箭头函数。

您可以简单地使用函数的bind 来更改函数的作用域:

function callback() {
  // How to access the button that was clicked?
  $("span").text(this.text());
}

var b = $('.button'); // in Typescript you should be using let instead of var
b.click(callback.bind(b));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button class='button'>Hello, world!</button>
<span></span>

对于其他复杂场景,你想同时使用箭头函数并在同一上下文中调用其他函数,你可以使用Function's callor apply

// let's suppose your callback function expects a Date and a Number param
$('.button').click(() => callback.call(this, new Date(), 23));
// or
$('.button').click(() => callback.apply(this, [new Date(), 23]));

【讨论】:

  • OP 希望同时访问this(外部作用域之一和回调函数之一),理想情况下仅从粗箭头函数访问。您所做的只是重新绑定this 以获得“完整”回调函数。
  • 确实,此解决方案在您注册事件处理程序时有权访问您希望this 在触发事件时拥有的值时才有效.考虑委托事件的情况,例如$('#button-container').on('click', '.button', callback)。在这种情况下,您无法事先知道单击了哪个按钮,也无法将.bind 传递给参数(事实上,this 实际上有许多可能的值,具体取决于存在的按钮)。
  • 哦,对不起,我误解了这个问题。感谢您的澄清!
猜你喜欢
  • 2012-09-20
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 2021-06-23
  • 2014-01-05
  • 2017-04-26
  • 1970-01-01
  • 2018-02-01
相关资源
最近更新 更多