在 class 方法中将变量传递给函数
Passing variable to function within class method
我有一个 class 我正在尝试编写如下所示的内容。
当我 运行 class 时,我得到一个错误:
Audio.js:53 Uncaught ReferenceError: bufferLength is not defined
我认为这是因为 bufferLength
在 drawCanvas
函数中不可用。
我试过添加 this
关键字,但是没有用。
如何使这些变量可用于此 class 的方法中的函数?
export const LINE_COLORS = ['rgba(255, 23, 204, 0.5)', 'rgba(130, 23, 255, 0.5)'];
// The dimensions of the current viewport
// - Used to set canvas width & height
export const PAGE_DIMENSIONS = {
width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
};
class AudioEngine {
constructor(params) {
this.params = params;
this.audio = new Audio();
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
this.analyser = this.ctx.createAnalyser();
this.source = this.ctx.createMediaElementSource(this.audio);
this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
this.bufferLength = this.analyser.frequencyBinCount;
this.canvas = document.getElementById(params.waveform);
this.onInit();
}
onInit() {
this.ConfigAudio();
this.DrawAudioWave();
}
ConfigAudio = () => {
this.audio.src = this.params.stream;
this.audio.controls = false;
this.audio.autoplay = false;
this.audio.crossOrigin = 'anonymous';
this.analyser.smoothingTimeConstant = 0.6;
this.source.connect(this.ctx.destination);
this.source.connect(this.analyser);
this.analyser.fftSize = 2048;
this.analyser.getByteFrequencyData(this.dataArray);
document.body.appendChild(this.audio);
};
DrawAudioWave = () => {
// Bind to the context
const canvasCtx = this.canvas.getContext('2d');
function drawCanvas() {
// We always start the drawing function by clearing the canvas. Otherwise
// we will be drawing over the previous frames, which gets messy real quick
canvasCtx.clearRect(0, 0, PAGE_DIMENSIONS.width, PAGE_DIMENSIONS.height);
requestAnimationFrame(drawCanvas);
const sliceWidth = (PAGE_DIMENSIONS.width * 1.0) / bufferLength;
// Create a new bounding rectangle to act as our backdrop, and set the
// fill color to black.
canvasCtx.fillStyle = '#000';
canvasCtx.fillRect(0, 0, PAGE_DIMENSIONS.width, PAGE_DIMENSIONS.height);
// Loop over our line colors. This allows us to draw two lines with
// different colors.
LINE_COLORS.forEach((color, index) => {
let x = 0;
// Some basic line width/color config
canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = color;
// Start drawing the path
canvasCtx.beginPath();
for (let i = 0; i < bufferLength; i++) {
// We offset using the loops index (stops both colored lines
// from overlapping one another)
const v = dataArray[i] / 120 + index / 20;
// Set the Y point to be half of the screen size (the middle)
const y = (v * PAGE_DIMENSIONS.height) / 2;
if (i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
canvasCtx.lineTo(canvas.width, canvas.height / 2);
canvasCtx.stroke();
});
}
drawCanvas();
};
audioToggle = () => (this.audio.paused ? this.audio.play() : this.audio.pause());
}
export default AudioEngine;
requestAnimationFrame 将在全局上下文绑定的情况下调用 drawCanvas,因此不会定义 this.bufferLength
。最简单的解决方案是利用 lexical scoping,箭头函数使它变得简单。
如果您查看如何定义 class 的方法,就会发现它们使用的是箭头函数。这正是为了避免您当前遇到的重新绑定 this
的问题。您应该阅读 this
和 JavaScript 中的范围界定,以更好地理解为什么您的代码无法按预期工作。
两个解决方案,都需要 drawCanvas -> this.drawCanvas
:
(A) 在将drawCanvas传递给requestAnimationFrame之前绑定它的上下文:
requestAnimationFrame(drawCanvas.bind(this))
或者 (B) 利用词法范围:
requestAnimationFrame(() => drawCanvas())
"Lexical" 范围是从 "text" 派生的范围,即你的箭头函数是相对于其他范围定义的。非词法作用域使用调用函数来确定绑定上下文。
您还可以使用 .bind
或将其更改为箭头函数来更改 drawCanvas
函数本身以绑定到适当的范围。
进一步阅读:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
- How does the "this" keyword work?
- Pass correct "this" context to setTimeout callback?(在他们的示例中将
setTimeout
替换为 requestAnimationFrame
)
我有一个 class 我正在尝试编写如下所示的内容。
当我 运行 class 时,我得到一个错误:
Audio.js:53 Uncaught ReferenceError: bufferLength is not defined
我认为这是因为 bufferLength
在 drawCanvas
函数中不可用。
我试过添加 this
关键字,但是没有用。
如何使这些变量可用于此 class 的方法中的函数?
export const LINE_COLORS = ['rgba(255, 23, 204, 0.5)', 'rgba(130, 23, 255, 0.5)'];
// The dimensions of the current viewport
// - Used to set canvas width & height
export const PAGE_DIMENSIONS = {
width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
};
class AudioEngine {
constructor(params) {
this.params = params;
this.audio = new Audio();
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
this.analyser = this.ctx.createAnalyser();
this.source = this.ctx.createMediaElementSource(this.audio);
this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
this.bufferLength = this.analyser.frequencyBinCount;
this.canvas = document.getElementById(params.waveform);
this.onInit();
}
onInit() {
this.ConfigAudio();
this.DrawAudioWave();
}
ConfigAudio = () => {
this.audio.src = this.params.stream;
this.audio.controls = false;
this.audio.autoplay = false;
this.audio.crossOrigin = 'anonymous';
this.analyser.smoothingTimeConstant = 0.6;
this.source.connect(this.ctx.destination);
this.source.connect(this.analyser);
this.analyser.fftSize = 2048;
this.analyser.getByteFrequencyData(this.dataArray);
document.body.appendChild(this.audio);
};
DrawAudioWave = () => {
// Bind to the context
const canvasCtx = this.canvas.getContext('2d');
function drawCanvas() {
// We always start the drawing function by clearing the canvas. Otherwise
// we will be drawing over the previous frames, which gets messy real quick
canvasCtx.clearRect(0, 0, PAGE_DIMENSIONS.width, PAGE_DIMENSIONS.height);
requestAnimationFrame(drawCanvas);
const sliceWidth = (PAGE_DIMENSIONS.width * 1.0) / bufferLength;
// Create a new bounding rectangle to act as our backdrop, and set the
// fill color to black.
canvasCtx.fillStyle = '#000';
canvasCtx.fillRect(0, 0, PAGE_DIMENSIONS.width, PAGE_DIMENSIONS.height);
// Loop over our line colors. This allows us to draw two lines with
// different colors.
LINE_COLORS.forEach((color, index) => {
let x = 0;
// Some basic line width/color config
canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = color;
// Start drawing the path
canvasCtx.beginPath();
for (let i = 0; i < bufferLength; i++) {
// We offset using the loops index (stops both colored lines
// from overlapping one another)
const v = dataArray[i] / 120 + index / 20;
// Set the Y point to be half of the screen size (the middle)
const y = (v * PAGE_DIMENSIONS.height) / 2;
if (i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
canvasCtx.lineTo(canvas.width, canvas.height / 2);
canvasCtx.stroke();
});
}
drawCanvas();
};
audioToggle = () => (this.audio.paused ? this.audio.play() : this.audio.pause());
}
export default AudioEngine;
requestAnimationFrame 将在全局上下文绑定的情况下调用 drawCanvas,因此不会定义 this.bufferLength
。最简单的解决方案是利用 lexical scoping,箭头函数使它变得简单。
如果您查看如何定义 class 的方法,就会发现它们使用的是箭头函数。这正是为了避免您当前遇到的重新绑定 this
的问题。您应该阅读 this
和 JavaScript 中的范围界定,以更好地理解为什么您的代码无法按预期工作。
两个解决方案,都需要 drawCanvas -> this.drawCanvas
:
(A) 在将drawCanvas传递给requestAnimationFrame之前绑定它的上下文:
requestAnimationFrame(drawCanvas.bind(this))
或者 (B) 利用词法范围:
requestAnimationFrame(() => drawCanvas())
"Lexical" 范围是从 "text" 派生的范围,即你的箭头函数是相对于其他范围定义的。非词法作用域使用调用函数来确定绑定上下文。
您还可以使用 .bind
或将其更改为箭头函数来更改 drawCanvas
函数本身以绑定到适当的范围。
进一步阅读:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
- How does the "this" keyword work?
- Pass correct "this" context to setTimeout callback?(在他们的示例中将
setTimeout
替换为requestAnimationFrame
)