setTimeout返回带有Uncaught TypeError的错误:Chrome中的AudioContext中的非法调用

时间:2015-04-15 02:55:21

标签: javascript audiocontext

在Chrome中,我首先使用AudioContext创建连续音色:

var audioCtx = new (window.AudioContext || window.webkitAudioContext);

var oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();

oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

oscillator.start();

现在我想在几毫秒后停止它。所以我这样做:

setTimeout(oscillator.stop, 500)

这会返回错误Uncaught TypeError: Illegal invocation

但是,如果我这样做;

setTimeout(function(){oscillator.stop()}, 500)

它工作正常。

我想现在为什么第一个不起作用并返回错误。这似乎是直截了当的方式。

1 个答案:

答案 0 :(得分:7)

您的原始代码不起作用,因为stop函数在没有任何上下文的情况下传递给setTimeout - 它不知道它应该作用于哪个对象。如果你调用,就像这样:

oscillator.stop();

然后在stop内,特殊变量this设置为oscillator指向的对象。但如果你这样说:

var x = oscillator.stop;

实际上并未调用该函数。相反,只是从oscillator提取对函数的引用并存储在别处。该函数不记得它来自何处,并且可以同时存储在许多不同的变量或对象属性中。例如:

var x = {};
x.foo = oscillator.stop;
x.foo();

最后一行调用stop,上下文为xthis设置为x)而不是oscillator。 (函数的主体会导致错误,因为stop会假设它的上下文是什么样的,但调用本身是合法的。)或者,如果你这样做:

var foo = oscillator.stop;
foo();

然后将仅使用默认上下文调用stop。在严格模式下,this将设置为undefined,而在非严格模式下,this将设置为window

执行此操作时:

setTimeout(function(){oscillator.stop()}, 500)

匿名函数使用适当的上下文调用stop。如果@elclanrs在评论中建议你这样做:

setTimeout(oscillator.stop.bind(oscillator), 500)

实际上它是一样的:创建一个匿名函数,调用stop,其上下文为oscillator