AudioBufferSourceNode.stop() 是否需要 'this' 绑定?

Should AudioBufferSourceNode.stop() need a 'this' binding?

以下代码创建一个在 500 毫秒后停止的音调。非常简单:

// Create audio context and nodes
var audioContext = new AudioContext();
var oscillator = audioContext.createOscillator();
oscillator.type = 'sine';
oscillator.frequency.value = 250;

// Attach nodes and start tone
oscillator.connect(audioContext.destination);
oscillator.start();

// Stop the tone after half a second
window.setTimeout(function() {
    oscillator.stop();
}, 500);

但是当我重构对 oscillator.stop() 的调用以简单地将函数指针传递给 window.setTimeout 时,它不再有效 - 至少在 Chrome:

window.setTimeout(oscillator.stop, 500); // throws 'Illegal Invocation' exception

这最初让我感到困惑 - 调用之间唯一真正的区别是在第二个调用中没有 this 绑定到 oscillator。显式绑定 this 确实解决了问题:

window.setTimeout(oscillator.stop.bind(oscillator), 500); // works perfectly

这是否应该是 AudioBufferSourceNode.stop() 需要被调用的方式(在 'this' 上下文中),或者这只是 Chrome 实现中的一个缺点(大概属于回到 JS 而不是直接调用本机代码)?我是否应该假定所有 BOM 方法都需要 this 绑定?

是的,一般来说,绑定是必要的。有了这个:

setTimeout(oscillator.stop, 500);

只有 stop() 被引用为孤立的 method/function,而不是 "context" 它所属的部分,因此当它被调用时 stop() 期望 oscillator作为上下文 (this) 但得到 window 当然会失败。

调用本机代码的方法也需要进行适当的绑定,因为它们是通过 JavaScript 公开的。另一个例子是:

var getId = document.getElementById;
getId("someId");    // will fail

var getId = document.getElementById.bind(document);
getId("someId");    // will work

所以这里需要绑定

你为什么要这样做?你应该使用

oscillator.stop( audio context.current time + 0.5 );

而是在调用 start() 之后立即执行。