create multiple objects with loop in constructor function - javascript

I have a problem when trying to create multiple objects in the function of a constructor function.
I'm trying to create multiple objects that each one has the array hand, and each one has the name player(x), so it would be player0: [array], player1:[array], but it does not work. I get the error
Cannot set property '0' of undefined
Code:
function Player () {
this.hand = []
}
function Players () {
}
Players.prototype.createPlayers = function (x) {
for (let i = 0; i < x; i++) {
this.player[i] = new Player()
}
}
let gamer = new Players()
console.log(gamer)
gamer.createPlayers(3)
console.log(gamer.players)

This is working try it, Is this you want?
function Player () {
this.hand = []
}
function Players () {
this.player = [];
}
Players.prototype.createPlayers = function (x) {
for (let i = 0; i < x; i++) {
this.player[i] = new Player()
}
}
let gamer = new Players()
console.log(gamer)
gamer.createPlayers(3)
console.log(gamer.players)

Related

JS queue array debug error

I am receiving this error,
Practice.html:formatted:20 Uncaught TypeError: queueArray.push is not a function
at Queue.add (Practice.html:formatted:20)
at Practice.html:formatted:30
but push isn't supposed to be a function. It is supposed to be a method executed on an array. So what could this mean??
var tickerArray = ['BP', 'AMZN', 'EARK'];
//also tried putting queueArray here because that would make it global, so i guess it isnt a scope issue?
function Queue() {
this.top = 0; //first item in the stack
var queueArray = []; //array to hold items
}
Queue.prototype.add = function(obj) {
queueArray.push(obj);
}
Queue.prototype.get = function() {
return queueArray.splice(this.top, 1);
}
var queueArray = new Queue();
for (i = 0; i < tickerArray.length; i++) {
queueArray.add(tickerArray[i]);
}
console.log(q.get());
Set queueArray as this.queueArray and return this.queueArray from .get()
var tickerArray = ['BP', 'AMZN', 'EARK'];
function Queue() {
this.top = 0; //first item in the stack
this.queueArray = []; //array to hold items
}
Queue.prototype.add = function(obj) {
this.queueArray.push(obj);
}
Queue.prototype.get = function() {
this.queueArray.splice(this.top, 1);
return this.queueArray; // `return` `this.queueArray` from the function
}
var queueArray = new Queue();
for (i = 0; i < tickerArray.length; i++) {
queueArray.add(tickerArray[i]);
}
console.log(queueArray.get());

JavaScript remove an IIFE event listener

I'm trying to remove click events from a list of id's after adding them with an IIFE like this
function setupPlayer(player){
var squareState = {};
for (i = 0; i < allSquares.length; i++) {
if(allSquares[i].innerHTML === "") {
// set up a click event for each square
document.getElementById(allSquares[i].getAttribute('id')).addEventListener('click', (clickSquare)(i));
}
}
}
The clickSquare function returns
function clickSquare(i){
var num = i;
return function() {
document.getElementById(allSquares[num].getAttribute('id')).innerHTML=player;
}
}
Then I try to remove them with
function removeClickEvents(){
for (let i = 0; i < allSquares.length; i++) {
document.getElementById(allSquares[i].getAttribute('id')).removeEventListener('click', clickSquare);
}
}
I've tried naming the returned anonymous function and using removeEventListener on that to no avail.
To remove event listener from a DOM element you need to pass the same function you used while adding event listener, as the parameter.
In javascript when you create an object it creates a new instance of that object class, so it won't be equal to another object even if it is created with same parameters
Example:
{} != {} // returns true
[] != [] // returns true
Same goes with function, whenever you write function (){} it creates a new instance of Function class.
Example:
function a() {
return function b() {}
}
a() != a() // returns true
Solution:
So for you to be able to remove the event listeners, you will have to store the functions you have passed to addEventListener
var listeners = [];
function setupPlayer(player) {
var squareState = {};
for (i = 0; i < allSquares.length; i++) {
if(allSquares[i].innerHTML === "") {
listeners[i] = clickSquare(i);
document.getElementById(allSquares[i].getAttribute('id')).addEventListener('click', listeners[i]);
}
}
}
function clickSquare(i) {
var num = i;
return function() {
document.getElementById(allSquares[num].getAttribute('id')).innerHTML=player;
}
}
function removeClickEvents() {
for (let i = 0; i < allSquares.length; i++) {
if(listeners[i]) {
document.getElementById(allSquares[i].getAttribute('id')).removeEventListener('click', listeners[i]);
}
}
}
From your code where you are using
document.getElementById(allSquares[i].getAttribute('id'))
I am assuming that allSquares[i] is a DOM element already, your code can be more simplified
var listeners = [];
function setupPlayer(player) {
var squareState = {};
for (i = 0; i < allSquares.length; i++) {
if(allSquares[i].innerHTML === "") {
listeners[i] = clickSquare(i);
allSquares[i].addEventListener('click', listeners[i]);
}
}
}
function clickSquare(i) {
var num = i;
return function() {
allSquares[num].innerHTML=player;
}
}
function removeClickEvents() {
for (let i = 0; i < allSquares.length; i++) {
if(listeners[i]) {
allSquares[i].removeEventListener('click', listeners[i]);
}
}
}
The function is being called immediately at (clickSquare)(i). At code at Question allSquares appears to be the element itself, clickSquare function can be referenced directly and event.target can be used within event handler to reference the current element in allSquares collection
let player = 123;
setInterval(() => player = Math.random(), 1000);
onload = () => {
let allSquares = document.querySelectorAll("div[id|=square]");
let button = document.querySelector("button");
button.onclick = removeClickEvents;
function setupPlayer(player) {
var squareState = {};
for (let i = 0; i < allSquares.length; i++) {
if (allSquares[i].innerHTML === "click") {
// set up a click event for each square
allSquares[i].addEventListener('click', clickSquare);
}
}
}
function clickSquare(event) {
console.log(event.target);
event.target.innerHTML = player;
}
function removeClickEvents() {
for (let i = 0; i < allSquares.length; i++) {
allSquares[i].removeEventListener('click', clickSquare);
}
}
setupPlayer(player);
}
<div id="square-0">click</div>
<div id="square-1">click</div>
<div id="square-2">click</div>
<button>remove events</button>

Javascript - Looping through classes and adding functions

I'm currently trying to create an HTML5 Canvas game and I want to be able to attach functions to buttons that activate when clicked. I can do this for unique functions but I'm struggling to find a way to do it when looping through many buttons with a predefined function.
I've created an example to show what I've tried so far:
jsFiddle: http://jsfiddle.net/ra1rb74w/1/
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction) {
this.aFunction = newFunction;
},
// Use the current function
useFunction: function () {
if (this.aFunction != null) {
this.aFunction;
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) { console.log(x); }
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction(x));
}
// Use the function in the first class
myClasses[0].useFunction();
You can see that all the functions get triggered which I don't want, and the useFunction() function doesn't work. Is there a way to do this?
So you are triggering baseFunction by calling baseFunction(x). You need to either get baseFunction to return a function which can be executed:
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction) {
this.aFunction = newFunction;
},
// Use the current function
useFunction: function () {
if (typeof this.aFunction === "function") {
this.aFunction.call(this);
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) {
return function() {
console.log(x);
};
}
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction);
}
// Use the function in the first class
myClasses[3].useFunction();
JsFiddle
Or add another parameter to addFunction which can be called like addFunction(baseFunction, x):
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction, value) {
this.aFunction = newFunction;
this.x = value;
},
// Use the current function
useFunction: function () {
if (typeof this.aFunction === "function") {
this.aFunction.call(this, this.x);
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) { console.log(x); }
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction, x);
}
// Use the function in the first class
myClasses[3].useFunction();
JsFiddle
Note I also changed your check for aFunction == null as the function passed in may be null, or a string, or anything else. You want to check if it is executable.
Change to
...
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction, x) {
this.aFunction = newFunction;
this.aFunctionX = x;
},
useFunction: function () {
if (this.aFunction != null) {
this.aFunction(this.aFunctionX);
}
}
};
...
...
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction, x);
}
...
Here is a fiddle http://jsfiddle.net/ra1rb74w/6/

'this' is unequal to Bar in prototype

In the following code snippet, 'this.x()' can only be called in case 2 (see main()).
Also Bar unequals this in case 1, but is equal for case 2.
function Class_Bar() {
this.panel = null;
this.init = function () {
// do some stuff
this.panel = 20;
}
this.apply = function () {
alert(Bar == this);
Bar.x();
this.x();
}
this.x = function() {
alert("Some friendly message");
alert(Bar.panel);
}
}
var Bar = new Class_Bar();
function Class_Factory() {
this.factories = new Array();
this.add = function (init, apply) {
this.factories.push({"init":init, "apply":apply});
}
this.init = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["init"]();
}
}
this.apply = function () {
for (var i = 0; i < this.factories.length; ++i) {
this.factories[i]["apply"]();
}
}
}
var Factory = new Class_Factory();
function main() {
// Case 1
Factory.add(Bar.init, Bar.apply);
Factory.init();
Factory.apply();
// Case 2
Bar.init();
Bar.apply();
}
main();
http://pastebin.com/fpjPNphx
Any ideas how to "fix" / workaround this behaviour?
I found a possible solution, but it seems to be a "bad" hack.: Javascript: How to access object member from event callback function
By passing Bar.init, you're really only passing the function but not the information that it belongs to Bar (i.e. what the this value should be). What you can do is binding that information:
Factory.add(Bar.init.bind(Bar), Bar.apply.bind(Bar));

variable assigned to anonymous function is not defined

I am using anonymous function assigned to a variable to minimize use of global variables. Within this function there are nested functions: one to preload and resize images, and two other nested functions for navigation (next and previous). The code below generates error that the variable to which the anonymous function is assigned is not defined:
Cannot read property 'preload_and_resize' of undefined
If you spot the problem please let me know. Thank you very much.
<html>
<head>
<script type="text/javascript">
var runThisCode=(function(){
var myImages=new Array("img/01.jpg","img/02.jpg","img/03.jpg");
var imageObj = new Array();
var index=0;
var preload_and_resize=function(){
var i = 0;
var imageArray = new Array();
for(i=0; i<myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
};
var next_image=function(){
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else{
index=0;
document.pic.src=imageObj[index].src;
}
};
var prev_image=function(){
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else{
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
};
})();
</script>
</head>
<body onload="runThisCode.preload_and_resize();">
<div align="center">
<img name="pic" id="pic" src="img/01.jpg"><br />
PrevNext
</div>
</body>
</html>
Your anonymous function doesn't return anything, so when you run it, undefined gets returned. That's why runThisCode is undefined. Regardless though, with the way you've written it, preload_and_resize will be local, so you wouldn't be able to access that anyway.
Instead, you want this anonymous function to construct an object, and reutrn that. Something like this should work, or at least get you close:
var runThisCode=(function(){
var result = {};
result.myImages=new Array("img/01.jpg","img/02.jpg","img/03.jpg");
result.imageObj = new Array();
result.index=0;
result.preload_and_resize=function(){
var i = 0;
var imageArray = new Array();
for(i=0; i< result.myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
};
result.next_image=function(){
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else{
index=0;
document.pic.src=imageObj[index].src;
}
};
result.prev_image=function(){
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else{
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
};
return result;
})();
This should explain what you are doing wrong :
var foobar = (function (){
var priv1, priv2 = 'sum' , etc;
return {
pub_function: function() {},
another: function() {
console.log('cogito ergo ' + priv2 );
}
};
})();
foobar.another();
You've assigned the function to the variable next_image which is scoped to the self-invoking anonymous function.
The value you assign to runThisCode is the return value of that anonymous function, which (since there is no return statement) is undefined.
To get the code to work you need to assign an object to runThisCode and make next_image a member of it.
Add the following to the end of the anonymous function:
return {
"next_image": next_image
}
Remove the anonymous function, and make your function public. You will only create one global variable: the object runThisCode.
var runThisCode = function () {
var myImages = new Array("img/01.jpg", "img/02.jpg", "img/03.jpg");
var imageObj = new Array();
var index = 0;
this.preload_and_resize = function () {
var i = 0;
var imageArray = new Array();
for (i = 0; i < myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src = myImages[i];
}
document.pic.style.height = (document.body.clientHeight) * 0.95;
};
this.next_image = function () {
index++;
if (index < imageObj.length) {
document.pic.src = imageObj[index].src;
} else {
index = 0;
document.pic.src = imageObj[index].src;
}
};
this.prev_image = function () {
index--;
if (index >= 0) {
document.pic.src = imageObj[index].src;
} else {
index = myImages.length - 1;
document.pic.src = imageObj[index].src;
}
};
};
And then, later in your code:
runThisCode.preload_and_resize();
should work.
From the invocation you've got in body onload property, it looks like what you're trying to achieve with the IIFE (immediately invoked function expression) is return an object that has a the method preload_and_resize.
As others have pointed out, you're not returning anything from the IIFE, so really all that's happening is you're closing up everything inside it in its own namespace, but not "exporting" anything.
If you want to "export" those functions, from your IIFE, you'd probably add a final bit to it that looked something like this:
return {
'preload_and_resize': preload_and_resize,
'next_image': next_image,
'prev_image': prev_image
}
which essentially creates a new JavaScript object literal, and then assigns its properties to the function values from the local scope.
Some developers would find this redundant and rather than finishing out with this sort of explicit export would probably just define the functions while declaring the object literal, something like:
return {
preload_and_resize: function(){
var i = 0;
var imageArray = new Array();
for(i=0; i<myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
},
next_image: function() {
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else {
index=0;
document.pic.src=imageObj[index].src;
}
},
prev_image: function() {
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else {
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
}
}
In respect of previous answers, my version:
function(self) {
let myImages = new Array("img/01.jpg", "img/02.jpg", "img/03.jpg");
let imageObj = new Array();
let index = 0; // if you need to expose this call with self.index
self.preload_and_resize = function() {
let i = 0;
let imageArray = new Array();
let (i = 0; i < myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src = myImages[i];
}
document.pic.style.height = (document.body.clientHeight) * 0.95;
};
var next_image = function() {
index++;
if (index < imageObj.length) {
document.pic.src = imageObj[index].src;
} else {
index = 0;
document.pic.src = imageObj[index].src;
}
};
var prev_image = function() {
index--;
if (index >= 0) {
document.pic.src = imageObj[index].src;
} else {
index = myImages.length - 1;
document.pic.src = imageObj[index].src;
}
};
})(window.myCurrentPage = window.myCurrentPage || {});
// now you canll myCurrentPage.preload_and_resize();

Categories