将变量传递给类方法中的函数

时间:2018-07-15 16:35:32

标签: javascript es6-class

我正在尝试编写一个类似于以下内容的类。

运行课程时,出现错误:

Audio.js:53 Uncaught ReferenceError: bufferLength is not defined

我相信这是因为bufferLength函数中没有drawCanvas

我尝试添加this关键字,但这没有用。

如何使这些变量可用于此类方法中的函数?

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;

1 个答案:

答案 0 :(得分:3)

requestAnimationFrame将调用绑定了全局上下文的drawCanvas,因此将不会定义this.bufferLength。最简单的解决方案是利用lexical scoping的优势,箭头功能使该操作变得简单。

如果您查看如何定义类的方法,则它们使用的是箭头函数。正是为了避免重新绑定您当前拥有的this的问题。您应该阅读this并在JavaScript中进行范围界定,以更好地理解为什么代码无法按预期工作。

夫妇的解决方案,都需要drawCanvas -> this.drawCanvas

(A)在将drawCanvas的上下文传递给requestAnimationFrame之前将其绑定:

requestAnimationFrame(drawCanvas.bind(this))

或者(B)进行词汇范围界定:

requestAnimationFrame(() => drawCanvas())

“词法”作用域是从“文本”派生的作用域,即您的箭头函数是相对于其他作用域定义的。非词法作用域使用调用方函数来确定绑定上下文。

您还可以使用drawCanvas.bind函数本身更改为绑定到适当的范围,或将其更改为箭头函数。

进一步阅读