Javascript 当requestAnimationFrame调用-ES6时,画布无法找到上下文

Javascript 当requestAnimationFrame调用-ES6时,画布无法找到上下文,javascript,css,ecmascript-6,babeljs,Javascript,Css,Ecmascript 6,Babeljs,我正在试验基于类的代码。我为画布创建一个类,并向其传递一个组件,然后对其进行渲染。问题是,当浏览器请求动画帧时,上下文将丢失,并且变得未定义。我正在寻找一个解释,为什么会出现这种情况 我不关心最佳实践,只是想弄清楚为什么失去了上下文 我已经附加了一个链接到codepen上的示例 以下是JS代码: class Canvas { constructor() { this.canvas = document.getElementById('canvas'); this.conte

我正在试验基于类的代码。我为画布创建一个类,并向其传递一个组件,然后对其进行渲染。问题是,当浏览器请求动画帧时,上下文将丢失,并且变得未定义。我正在寻找一个解释,为什么会出现这种情况

我不关心最佳实践,只是想弄清楚为什么失去了上下文

我已经附加了一个链接到codepen上的示例

以下是JS代码:

class Canvas {
  constructor() {
    this.canvas = document.getElementById('canvas');
    this.context = this.canvas.getContext('2d');
    this.width = this.canvas.width = window.innerHeight;
    this.height = this.canvas.height = window.innerWidth;
    this.components = [];
  }

  draw() {
    this.context.clearRect(0, 0, this.width, this.height);
    this.context.globalCompositeOperation = 'hard-light';

    this.components.map(_ => _.render());

    window.requestAnimationFrame(this.draw);
  }

  listeners() {
    window.addEventListener('resize', () => {
      this.width = this.canvas.width = window.innerHeight;
      this.height = this.canvas.height = window.innerWidth;
    }, false);
  }

  init() {
    this.listeners();
    this.draw();
  }
}

class Utils {
  randomNum(max, min) {
    return Math.floor(max * Math.random()) + min;
  }

  color(opacity) {
    return `hsla(${this.randomNum(360, 1)}, 70%, 60%, ${opacity})`;
  }
}

const utils = new Utils();
const _canvas = new Canvas();

class Stars {
  constructor(_) {
    this.total = _.total;
    this.spawn = [];
    this.z = 300;
    this.canvas = _.canvas;
    this.xw = this.canvas.width * this.z;
    this.xh = this.canvas.height * this.z;
  }

  create() {
    while (this.spawn.length < this.total) {
      this.spawn.push({
        pos: [this.xw * Math.random() - this.canvas.width / 2 * this.z, this.xh * Math.random() - this.canvas.height / 2 * this.z, this.z],
        vel: [0, 0, -2],
        r: utils.randomNum(500, 100),
        color: utils.color(1)
      });
    }
  }

  draw() {
    for (let i = 0; i < this.spawn.length; ++i) {
      let t = this.spawn[i];
      let x = t.pos[0] / t.pos[2];
      let y = t.pos[1] / t.pos[2];
      if (x < -this.canvas.width / 2 || x > this.canvas.width / 2 || y < -this.canvas.height / 2 || y > this.canvas.height / 2 || t.pos[2] < 0) {
        this.spawn.splice(i, 1);
        --i;
        continue;
      }
      this.canvas.context.beginPath();
      this.canvas.context.fillStyle = t.color;
      this.canvas.context.arc(x, y, t.r / t.pos[2], 0, Math.PI * 2, false);
      t.pos[0] += t.vel[0];
      t.pos[1] += t.vel[1];
      t.pos[2] += t.vel[2];
      this.canvas.context.fill();
    }
  }

  render() {
    this.create();
    this.canvas.context.save();
    this.canvas.context.translate(this.canvas.width / 2, this.canvas.height / 2);
    this.draw();
    this.canvas.context.restore();
  }
}

_canvas.components.push(new Stars({
  canvas: _canvas,
  total: 200
}));
类画布{
构造函数(){
this.canvas=document.getElementById('canvas');
this.context=this.canvas.getContext('2d');
this.width=this.canvas.width=window.innerHeight;
this.height=this.canvas.height=window.innerWidth;
此参数为.components=[];
}
画(){
this.context.clearRect(0,0,this.width,this.height);
this.context.globalCompositeOperation='hard light';
this.components.map(=>u.render());
window.requestAnimationFrame(this.draw);
}
听众(){
window.addEventListener('resize',()=>{
this.width=this.canvas.width=window.innerHeight;
this.height=this.canvas.height=window.innerWidth;
},假);
}
init(){
this.listeners();
这个.draw();
}
}
类Utils{
随机数(最大值,最小值){
返回Math.floor(max*Math.random())+min;
}
颜色(不透明度){
返回`hsla(${this.randomNum(360,1)},70%,60%,${opacity})`;
}
}
const utils=新utils();
const_canvas=新画布();
班级明星{
构造函数{
this.total=uu.total;
this.spawn=[];
这个z=300;
this.canvas=ux.canvas;
this.xw=this.canvas.width*this.z;
this.xh=this.canvas.height*this.z;
}
创建(){
while(this.spawn.lengththis.canvas.width/2 | | y<-this.canvas.height/2 | | y>this.canvas.height/2 | | t.pos[2]<0){
this.spawn.splice(i,1);
--一,;
继续;
}
this.canvas.context.beginPath();
this.canvas.context.fillStyle=t.color;
this.canvas.context.arc(x,y,t.r/t.pos[2],0,Math.PI*2,false);
t、 位置[0]+=t.vel[0];
t、 位置[1]+=t.vel[1];
t、 位置[2]+=t.vel[2];
this.canvas.context.fill();
}
}
render(){
这个。create();
this.canvas.context.save();
this.canvas.context.translate(this.canvas.width/2,this.canvas.height/2);
这个.draw();
this.canvas.context.restore();
}
}
_画布。组件。推送(新星星)({
画布:_画布,
总数:200
}));
当您通过
窗口调用
draw()
时,
requestAnimationFrame(this.draw)
中的作用域绑定到
draw()
窗口,而不是
画布
。尝试显式绑定作用域,如下所示:

window.requestAnimationFrame(this.draw.bind(this));

真是太棒了。谢谢。或者,因为我们还是使用ES 6,
()=>this.draw()
。顺便说一句:绑定的不是范围,而是
this
的值。