在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)
它工作正常.
我想现在为什么第一个不起作用并返回错误.这似乎是直截了当的方式.
解决方法:
您的原始代码不起作用,因为stop函数在没有任何上下文的情况下传递给setTimeout – 它不知道它应该作用于哪个对象.如果你像这样调用它:
oscillator.stop();
然后在stop内,将特殊变量设置为振荡器指向的对象.但如果你像这样引用它:
var x = oscillator.stop;
实际上没有调用该函数.相反,只是从振荡器中提取对函数的引用并存储在别处.该函数不记得它来自何处,并且可以同时存储在许多不同的变量或对象属性中.例如:
var x = {};
x.foo = oscillator.stop;
x.foo();
最后一行使用x的上下文(设置为x)而不是振荡器调用stop. (函数的主体会导致错误,因为stop会假设它的上下文是什么样的,但调用本身是合法的.)或者,如果你这样做:
var foo = oscillator.stop;
foo();
然后只使用默认上下文调用stop.在严格模式下,这将设置为undefined,在非严格模式下,这将设置为window.
当你这样做:
setTimeout(function(){oscillator.stop()}, 500)
匿名函数使用适当的上下文调用stop.如果@elclanrs在评论中建议您执行此操作:
setTimeout(oscillator.stop.bind(oscillator), 500)
它实际上是一样的:创建一个匿名函数,用振荡器的上下文调用stop.