I'm going through a W3 schools tutorial on game controllers and there is an expression myGameArea.keys = (myGameArea.keys || [])
which I'm having trouble understanding and it would be great if someone could explain in detail what's the logic behind.
Tutorial explanation
What if more than one key is pressed at the same time?
In the example above, the component can only move horizontally or vertically. Now we want the component to also move diagonally.
Create a keys array for the myGameArea object, and insert one element for each key that is pressed, and give it the value true , the value remains true untill the key is no longer pressed, the value becomes false in the keyup event listener function:
Context of the expression
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = false;
})
Full JavaScript code
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = false;
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.speedX = -1; }
if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.speedX = 1; }
if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.speedY = -1; }
if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.speedY = 1; }
myGamePiece.newPos();
myGamePiece.update();
}
CodePudding user response:
In most programming languages, ||
is an operator that takes two boolean values and performs a logical OR on them. (true || false
is true
, etc.)
Some languages, primarily dynamically typed ones in my experience, generalize the notion of ||
to work with other datatypes as well.
In JavaScript, ||
means the following:
- If the first value is falsy (
0
,false
,""
,null
,undefined
,NaN
), return the second value. - Otherwise, return the first value.
If you plug in some boolean values, you can see that this behavior mimmicks how ||
work in other languages.
Because of this behavior, ||
gains a secondary use as a "default value" operator, i.e. "use this value unless it's falsy, in which case use this other value instead".
For instance:
let greeting = x || "Hello";
In the above code, greeting
will be set to x
unless x
is falsy, in which case it'll instead be set to "Hello"
.
Likewise,
this.foo = this.foo || "Yo!";
The above code will initialize this.foo
to "Yo!"
if it doesn't already exist (or exists but has a falsy value).
Edit:
Looking at this specific example in OP's post:
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
})
The line myGameArea.keys = (myGameArea.keys || []);
ensures that the myGameArea.keys
array exists, since it's never created before the event listener is registered and potentially invoked. You could explicitly add a keys: []
to the myGameArea
object to remove the need for this line altogether.
Additionally, the code also contains similar uses of the &&
operator. As with ||
, it too has been generalized in JavaScript. It works like this:
- If the first value is falsy, return the first value.
- Otherwise, return the second value.
Looking at its use in the if statement:
if (myGameArea.keys && myGameArea.keys[37]) { /*...*/ }
The myGameArea.keys &&
is a way to short-circuit the second half of the condition. If myGameArea.keys
was never created (for instance, because no button was ever pressed), we skip the rest of the condition which would otherwise have crashed since myGameArea.keys
would be undefined
and you cannot index ([37]
) into the undefined
value.