Global variable undefined inside a function - javascript

I am using webpack and have one global variable inside a module, when I try to return it from inside a function I get undefined. I do not really understand the scope since I thought I can access global variables from a functional and return them.
here is my code:
import Gameboard from './factory/gameboard';
import Player from './factory/player';
import helpers from './helpers';
import dom from './dom';
const game = (() => {
let gameStatus = false;
var player;
var computer;
let turn = 0;
const getPlayers = () => {
const name = 'Player1';
player = Player(name);
computer = Player('Computer');
};
const whosTurn = function whosTurn() {
if (turn % 2 === 0) {
return player;
}
return computer;
};
const getPeg = (index = null) => {
const playerTurn = whosTurn();
if (playerTurn.getName() === 'Computer') {
helpers().computerMove();
dom().createPlayerBoard(playerBoard);
} else {
const gameboard = computerBoard;
makeAttack(playerTurn, gameboard, index);
dom().createCompBoard(gameboard);
}
};
return {
getPlayers,
whosTurn,
getPeg,
};
});
export {
game as
default
};
I want the whosTurn function to return me the player or computer variable. What am I doing wrong?

Related

Use multiple SpeechRecognition() constructors to listen in multiple languages at the same time

I've setup a test script that successfully transcribes what I am saying, both in english and german if I set the lang property beforehand.
However, I want it to automatically recognize which language I am speaking. Since SpeechRecognition does not support this, my idea was to just use multiple constructors at the same time, each with their own lang property and then just use the transcription with the highest confidence score.
However, this does not seem to work, as chrome does not transcribe anything if i start both constructors at once. In fact, I have to close chrome alltogether before it will start working again.
Any ideas? Here is the full code, if I uncomment the commented lines it will not work.
function listenEN(){
navigator.webkitGetUserMedia(
{ audio: true },
() => {},
() => {},
)
let triggerPhrase = "Computer"
triggerPhrase = triggerPhrase ? triggerPhrase.toLowerCase() : "Alexa"
let voices = window.speechSynthesis.getVoices()
const voiceEN = voices.find((voice) => voice.name === 'Google US English')
const voiceDE = voices.find((voice) => voice.name === 'Google DE German')
async function notifyStartListening() {
const utterance = new SpeechSynthesisUtterance("beep!");
utterance.rate = 2;
utterance.pitch = 1.5;
utterance.voice = voiceEN;
speechSynthesis.speak(utterance);
}
const recognitionEN = new webkitSpeechRecognition()
recognitionEN.lang = 'en-US'
recognitionEN.continuous = true
const recognitionDE = new webkitSpeechRecognition()
recognitionDE.lang = 'de-DE'
recognitionDE.continuous = true
try {
let isActive = false
function startListening() {
notifyStartListening();
isActive = true
}
recognitionEN.addEventListener('result', async () => {
recognitionEN.lang = 'en-US'
const transcriptEN = event.results[event.results?.length - 1][0].transcript
console.log(transcriptEN)
if (isActive) {
let instruction = transcriptEN
if (transcriptEN.trimStart().startsWith(triggerPhrase)) {
instruction = transcriptEN.trimStart().substring(triggerPhrase.length)
}
isActive = false
return
}
const trimmed = transcriptEN.trimStart().trimEnd().toLowerCase()
if (trimmed.startsWith(triggerPhrase)) {
const instructionEN = trimmed.substring(triggerPhrase.length)
if (instructionEN && instructionEN?.length > 2) {
let confidenceEN = document.createElement('p')
confidenceEN.innerHTML = event.results[event.results?.length - 1][0].confidence
document.body.appendChild(confidenceEN);
} else {
startListening()
}
}
})
recognitionDE.addEventListener('result', async () => {
recognitionDE.lang = 'de-DE'
const transcriptDE = event.results[event.results?.length - 1][0].transcript
console.log(transcriptDE)
if (isActive) {
let instruction = transcriptDE
if (transcriptDE.trimStart().startsWith(triggerPhrase)) {
instruction = transcriptDE.trimStart().substring(triggerPhrase.length)
}
isActive = false
return
}
const trimmed = transcriptDE.trimStart().trimEnd().toLowerCase()
if (trimmed.startsWith(triggerPhrase)) {
const instructionDE = trimmed.substring(triggerPhrase.length)
if (instructionDE && instructionDE?.length > 2) {
let confidenceDE = document.createElement('p')
confidenceDE.innerHTML = event.results[event.results?.length - 1][0].confidence
document.body.appendChild(confidenceDE);
} else {
startListening()
}
}
})
recognitionEN.addEventListener('error', (event) => {
console.log(event)
})
recognitionEN.onend = function () {
recognitionEN.start()
}
recognitionEN.start()
/*recognitionDE.addEventListener('error', (event) => {
console.log(event)
})
recognitionDE.onend = function () {
recognitionDE.start()
}
recognitionDE.start() */
} catch (e) {
console.error(e)
}
}

Unable to minify javascript class

I have created a JavaScript class. I'm getting an error when I try to minify the code using javascript-minifier. Can you help me to fix this issue?
My code:
class Test {
onCompleted = () => {};
onDismissed = () => {};
onError = () => {};
isProgress = false;
popup;
payment;
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open('---');
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const Test = new Test();
window.addEventListener('beforeunload', function () {
if (Test.popup != null && !Test.popup.closed) {
Test.popup.close();
}
});
window.Test = Test;
Error message:
// Error : Unexpected token: operator (=)
// Line : 2
// Col : 18
The way you are creating the class seems to be wrong. In classes you can use functions like this: onCompleted() {}; and you can create variables in constructor. I also fixed an issue where you have Test defined twice, one as the class and one as variable. I renamed variable to TestInstance
Here would be a fixed example:
class Test {
constructor() {
this.isProgress = false;
this.popup;
this.payment;
}
onCompleted () {};
onDismissed () {};
onError () {};
startPayment(payment) {
this.payment = payment;
this.isProgress = true;
this.popup = window.open("---");
var timer = setInterval(function () {
if (this.Test.popup.closed) {
clearInterval(timer);
if (this.Test.isProgress) {
this.Test.isProgress = false;
this.Test.onDismissed();
}
}
}, 500);
}
}
const TestInstance = new Test();
window.addEventListener("beforeunload", function () {
if (TestInstance.popup != null && !TestInstance.popup.closed) {
TestInstance.popup.close();
}
});
window.Test = TestInstance;
A minified version:
class Test{constructor(){this.isProgress=!1,this.popup,this.payment}onCompleted(){}onDismissed(){}onError(){}startPayment(s){this.payment=s,this.isProgress=!0,this.popup=window.open("---");var t=setInterval(function(){this.Test.popup.closed&&(clearInterval(t),this.Test.isProgress&&(this.Test.isProgress=!1,this.Test.onDismissed()))},500)}}const TestInstance=new Test;window.addEventListener("beforeunload",function(){null==TestInstance.popup||TestInstance.popup.closed||TestInstance.popup.close()}),window.Test=TestInstance;

how to pass this keyword to javascript class functions

I'm running into the undefinded error when trying to access the this.numberObject from another function init.
I'm pretty sure it's because my this keyword is referencing the window object.
My problem is that I can't figure out an elegant way to structure my code.
Current Code:
class IncrementNumbers {
constructor() {
this.numberObject = document.querySelector(".incrementNum");
if (this.numberObject != null) {
console.log(this.numberObject.innerHTML);
this.num = this.numberObject.innerHTML;
this.events();
}
}
events() {
console.log("events function ran");
this.init();
}
init() {
let target = 345;
let current = 0;
function addOneToElement() {
if (current === target) {
clearInterval(addOne);
}
current++;
this.numberObject.innerHTML = current; <---- ERROR HERE
}
let addOne = setInterval(addOneToElement, 10);
}
}
export default IncrementNumbers;
Error:
IncrementNumbers.js:44 Uncaught TypeError: Cannot set property 'innerHTML' of undefined
I can fix the error by adding in
this.numberObject = document.querySelector(".incrementNum");
to the following function
init() {
let target = 345;
let current = 0;
function addOneToElement() {
this.numberObject = document.querySelector(".incrementNum"); <--- ADDED HERE
if (current === target) {
clearInterval(addOne);
}
current++;
this.numberObject.innerHTML = current;
}
let addOne = setInterval(addOneToElement, 10);
}
However this feels a bit redundant because I'm already referencing the element Object in my constructor. I'd like the function, init to run once the page has loaded.
Is there a better way?
Thank you
Your problem seems to come from a misspropagation of the this object.
In your function init you set a new function named addOneToElement that is called inside of a setInterval, this setInterval instance does not have access to the this element of your class.
To fix the problem you could try to do something like
class IncrementNumbers {
constructor() {
this.numberObject = document.querySelector(".incrementNum");
if (this.numberObject != null) {
console.log(this.numberObject.innerHTML);
this.num = this.numberObject.innerHTML;
this.events();
}
}
events() {
console.log("events function ran");
this.init();
}
init() {
let target = 345;
let current = 0;
function addOneToElement() {
if (current === target) {
clearInterval(addOne);
}
current++;
this.numberObject.innerHTML = current; // <---- ERROR HERE
}
let addOne = setInterval(addOneToElement.bind(this), 10);
}
}
export default IncrementNumbers;
let addOne = setInterval(addOneToElement.bind(this), 10);
Where you bind the this instance of your class to the function addOneToElement.
The problem is the inner function addOneToElement that creates its own this context within init.
A simple fix would be to use arrow functions which don't have a this context:
class IncrementNumbers {
init() {
let target = 345;
let current = 0;
// Use an arrow function here.
const addOneToElement = () => {
if (current === target) {
clearInterval(addOne);
}
current++;
this.numberObject.innerHTML = current; <---- ERROR HERE
}
let addOne = setInterval(addOneToElement, 10);
}
}
Another option would be to bind the this context to addOneToElement:
let addOne = setInterval(addOneToElement.bind(this), 10);

Module - IIFE isn't automatically called

I created a module but it is not automatically rendered in my page, I have to manually call Board.renderBoard() in the console for the Board to appear. What am I doing wrong ?
here's the entire code:
const Board = (() => {
const board = document.querySelector('.board');
const createTiles = () => {
tile = document.createElement('div');
tile.classList.add('tile');
return tile;
};
const renderBoard = () => {
for (let i = 0; i < 9; i++) {
createTiles();
board.appendChild(createTiles());
}
};
return {
renderBoard
};
})();
I created a module but it is not automatically rendered in my page, I have to manually call Board.renderBoard() in the console for the Board to appear.
JS doesn't just call function unless you tell it to call these functions.
Your module simply defines an object Board with a method renderboard. There's nothing that tells JS to call this method.
You could add the call right after declaring the module.
const Board = (() => {
...
})();
Board.renderBoard();
But if all you want is that the code initially builds the board you can do:
(() => {
const board = document.querySelector('.board');
const createTiles = () => {
const tile = document.createElement('div'); // please declare your variables
tile.classList.add('tile');
return tile;
};
for (let i = 0; i < 9; i++) {
createTiles(); // what is this line for?
board.appendChild(createTiles());
}
})();
or
(() => {
const board = document.querySelector('.board');
for (let i = 0; i < 9; i++) {
const tile = document.createElement('div');
tile.classList.add('tile');
board.appendChild(tile);
}
})();
or maybe even
document.querySelector('.board').innerHTML = '<div class="tile"></div>'.repeat(9);

Passing references of a class to another class and using its methods

Let's say you're making a game. You want to try and not pollute the global scope and possibly limit the user's ability to easily alter the game (doubtful with client-side). You feel like modules might be unnecessary for your purposes. Is it bad practice to pass references to a class to another class during instantiation to access its methods?
Contrived example:
//game.js
var Game = (function () {
function Game() {
this.currentLevel = null;
this.score = 0;
}
Game.prototype.addScore = function (num) {
this.score += num;
};
Game.prototype.goToLevel = function (diff) {
this.currentLevel = new Level(this, diff);
};
Game.prototype.returnHome = function (level) {
this.currentLevel = null;
};
return Game;
})();
//level.js
var Level = (function () {
function Level(game, difficulty) {
this.game = game; //reference to game
this.difficulty = difficulty;
this.entities = [];
this.load();
}
Level.prototype.load = function () {
this.addEntity({name: 'tim', power: 23, difficulty: this.difficulty});
};
Level.prototype.leave = function () {
this.game.returnHome();
};
Level.prototype.addEntity = function (options) {
this.entities.push(new Entity(this, options));
};
Level.prototype.removeEntity = function (entity) {
for(var x = 0; x < this.entities.length; x++) {
if(this.entities[x] === entity) this.entities.splice(x, 1);
}
};
return Level;
})();
//level.js
var Entity = (function () {
function Entity(level, options) {
this.level = level; //reference to level
this.options = options;
}
Entity.prototype.kill = function () {
this.level.removeEntity(this); // anti-pattern?
this.level.game.addScore(34.53); // too closely coupled?
};
return Entity;
})();
//main.js
var Main;
(function (Main) {
var game = null;
function documentIsReady() {
start(); // Start the game
}
function start() {
game = new Game();
game.goToLevel('hard');
}
return {
documentIsReady: documentIsReady
}
})(Main || (Main = {}));
$(document).ready(function () {
Main.documentIsReady();
});
Forgive the half-baked example. If you end up with many instances of the 'Entity' class, do all the references to 'Level', though the same instance, start taking more memory? Are there other pitfalls? Another method would be to implement some kind of interface that you can access that allow classes to talk to each other.

Categories