克隆俄罗斯方块时箭头函数报错“shape未定义”,求问题排查与方案
一、"shape未定义"错误的原因及修复方案
看你的代码写法和执行顺序,有几个关键问题导致了这个报错:
构造函数调用顺序颠倒
你先执行了let Piece = new shapes(...),然后才定义shapes箭头函数。JavaScript是从上到下执行的,当执行new shapes时,shapes还没被定义(就算你注释里写了导入,后面重新赋值的操作也会覆盖之前的导入,而且顺序完全不对),自然会抛出“未定义”的错误。箭头函数不能作为构造函数使用
箭头函数没有自己的prototype属性,也不绑定独立的this,所以根本不能用new关键字来实例化对象。你想用shapes作为生成方块的构造函数,必须改用普通函数或者ES6的class语法。未声明变量导致的作用域污染
你在shapes函数内部的piece、color、orientation、x、y等变量都没有用let/const声明,会自动挂载到全局作用域,不仅容易和其他变量冲突,还可能导致后续逻辑出现莫名其妙的问题。
修复后的代码示例(改用普通构造函数):
// 先定义构造函数,再进行实例化 function Shape(shape, color) { this.piece = shape; this.color = color; this.orientation = 0; this.activePiece = this.piece[this.orientation]; this.x = 3; this.y = 1; this.draw = () => { // 注意row和col也要声明,避免全局变量污染 for (let row = 0; row < this.activePiece.length; row++) { for (let col = 0; col < this.activePiece.length; col++) { if (this.activePiece[row][col] === 1) { drawSquare(this.x + col, this.y + row, this.color); } } } }; this.moveDown = () => { this.y++; this.draw(); }; } // 假设pieces已正确导入 let Piece = new Shape(pieces[0][0], pieces[0][1]); Piece.draw(); Piece.moveDown();
如果用ES6 Class会更清晰易维护:
class Shape { constructor(shape, color) { this.piece = shape; this.color = color; this.orientation = 0; this.activePiece = this.piece[this.orientation]; this.x = 3; this.y = 1; } draw() { for (let row = 0; row < this.activePiece.length; row++) { for (let col = 0; col < this.activePiece.length; col++) { if (this.activePiece[row][col] === 1) { drawSquare(this.x + col, this.y + row, this.color); } } } } moveDown() { this.y++; this.draw(); } } let Piece = new Shape(pieces[0][0], pieces[0][1]); Piece.draw(); Piece.moveDown();
二、在Shape内部实现方块下落逻辑是否可行?
完全可行!你现在的moveDown方法已经是内部实现下落的基础逻辑了,不过可以再优化完善:
添加碰撞检测
现在的代码只会让y值增加,但没有检测方块是否碰到底部或其他已固定的方块,会直接“掉出”游戏区域。可以给Shape添加碰撞检测方法:moveDown() { // 假设你有canMoveDown方法判断是否可继续下落 if (this.canMoveDown()) { this.y++; this.draw(); return true; } else { // 无法下落时,固定当前方块到游戏板,生成新方块 this.lockToBoard(); return false; } }实现自动下落
如果你想让方块自动下落,可以用定时器或requestAnimationFrame循环调用moveDown:// 用setInterval实现固定间隔下落 function startAutoDrop(piece) { setInterval(() => { piece.moveDown(); }, 1000); // 每秒下落一次,可调整速度 } let Piece = new Shape(pieces[0][0], pieces[0][1]); Piece.draw(); startAutoDrop(Piece);用
requestAnimationFrame会更流畅,需要控制时间间隔避免下落过快:let lastDropTime = 0; function autoDrop(timestamp, piece) { if (timestamp - lastDropTime > 1000) { piece.moveDown(); lastDropTime = timestamp; } requestAnimationFrame((time) => autoDrop(time, piece)); } let Piece = new Shape(pieces[0][0], pieces[0][1]); Piece.draw(); requestAnimationFrame((time) => autoDrop(time, Piece));
内容的提问来源于stack exchange,提问作者user3398356

