Javascript function error : length undefined - javascript

I am a novice JavaScript user learning about how to code functions in a sustainable and clean way.
But I came across some problems and it throws an error such as console undefined or length undefined and I don't know why it happens like that.
//objects
var lists = [{
ignore: true,
accept: true
},
{
meaning: true
}
];
var start1 = processthings(lists, start);
if (!start1) {
console.log("wrong! start it first!")
};
var dictionary1 = processthings(lists, dictionary);
if (!dictionary1) {
console.log("look it up!")
};
//comprehensive process function
function processthings(lists, cfunctions) {
for (var i = 0; i < lists.length; i++) {
if (cfunctions(lists[i])) {
return true;
};
return false;
};
};
//each function : number 1
function start(element) {
return (element.ignore == true);
};
// each functon : number 2
function dictionary(element) {
return (element.meaning);
};

The for loop in function processthings will never iterate through the entire list. The function will always return after the first iteration.
I am not sure whether that is done intentionally or not. But I think the function should be modified as below -
//comprehensive process function
function processthings (lists,cfunctions){
var flag = false;
for (var i=0; i< lists.length; i++){
if (cfunctions(lists[i])){
flag = true;
break;
};
};
return flag;
};
See the working code here

Related

Breaking from a recursive function and returning a value in Javascript

I have written a javascript function like this . But I want when a cretain condition meet the function will not execute means it will break and return a true false like status.My code is like this
var ActionAttributes = function (data)
{
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey==''||attrKey==null)
{
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++)
{
var childData = data.Children()[i];
ActionAttributes(childData);
}
return status;
}
You need break condition in the for loop. You are just invoking it, handle the returned status.
var ActionAttributes = function(data) {
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey == '' || attrKey == null) {
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++) {
var childData = data.Children()[i];
//You need to break loop here
//Add appropriate condition here
if (ActionAttributes(childData) == false) {
return false;
}
}
return status;
}
well, that recursion is not very useful to begin with.
you call a recursion of ActionAttributes inside the loop, but never handle the returned status. So the first caller will always receive true unless the exit condition meets on the first object.
you shoul store the return from ActionAttributes into status, and then break out of the loop as soon as it's false.

How to return from the above nested function?

The below function will always return true, because the return false; returns the function passed to forEach.
function exampleFunction(array){
array.forEach(function(element){
if(element.condition){
return false;
}
});
return true;
}
Now, obviously the below works:
function exampleFunction(array){
var result = true;
array.forEach(function(element){
if(element.condition){
result = false;
}
});
return result;
}
but it's not ideal because it does unnecessary iterations. I know I could solve the problem by using a different loop to forEach, but I'm wondering if there's a way to do it keeping forEach. So, how can I return from the 'above' function in JavaScript when inside a nested function?
There's no way to break a .forEach loop during the loop other than throwing an exception (but don't do that). Use a for loop if you need to break mid-way. If you really need a method or a function:
function forEach(arr, func) {
for (var i = 0; i < arr.length; i++) {
if (func(arr[i], i) === false) {
break;
}
}
}
// Or...
Array.prototype.softLoop = function(func) {
for (var i = 0; i < this.length; i++) {
...
}
var my_array = [0, 1, 2, 3];
my_array.softLoop(function(element, index) {
console.log(index, element);
if (element == 2) {
return false;
}
});
You could even modify it so you didn't need a flag outside the loop:
Array.prototype.softLoopReturnable = function(func) {
for (var ret, i = 0; i < this.length; i++) {
ret = func(arr[i], i);
if (ret === false) {
break;
}
}
return ret;
}
You could use Array.prototype.some:
function exampleFunction(array){
return !array.some(function(element){
return element.condition;
});
}
In the code above, exampleFunction will return false when it comes across the first element where condition is truthy or true if none are found.
You can short circuit the forEach by throwing an exception, but a better way would be to use Array.prototype.some():
function doesNotContainOnes(array){
return !array.some(function(el) { return el === 1; });
}
document.body.innerHTML = doesNotContainOnes([5,9,6]) + '<br>' // true
+ doesNotContainOnes([5,9,6,'hi']) + '<br>' // true
+ doesNotContainOnes([5,9,6,1]) + '<br>'; // false

Simplify the code by using cycle function

I have multiply functions which are using the same cycle code and i'm wondering is it possible to simplify the code by having one cycle function so i could execute the code just by calling wanted function names.
Now:
for(var i=0;i<all;i++){ someFunction(i) }
Need:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
name(i);
}
}
I tried to do this by using "window" and i get no error but the function is not executed.
var MyLines = new lineGroup();
MyLines.createLines(); // works
MyLines.addSpeed(); // doesn't work
var lineGroup = function(){
this.lAmount = 5,
this.lines = [],
this.createLines = function (){
for(var i=0,all=this.lAmount;i<all;i++){
this.lines[i] = new line();
}
},
this.addSpeed = function (){
// no error, but it's not executing addSpeed function
// if i write here a normal cycle like in createLines function
// it's working ok
this.linesCycle("addSpeed");
},
this.linesCycle = function(callFunction){
for(var i=0,all=this.lAmount;i<all;i++){
window['lineGroup.lines['+i+'].'+callFunction+'()'];
}
}
}
var line = function (){
this.addSpeed = function (){
console.log("works");
}
}
window['lineGroup.lines['+i+'].'+callFunction+'()'];
literally tries to access a property that starts with lineGroups.lines[0]. Such a property would only exist if you explicitly did window['lineGroups.lines[0]'] = ... which I'm sure you didn't.
There is no need to involve window at all. Just access the object's line property:
this.lines[i][callFunction]();
i get no error but the function is not executed.
Accessing a non-existing property doesn't generate errors. Example:
window[';dghfodstf0ap9sdufgpas9df']
This tries to access the property ;dghfodstf0ap9sdufgpas9df, but since it doesn't exist, this will result in undefined. Since nothing is done with the return value, no change can be observed.
Without a name space use:
window["functionName"](arguments);
SO wrap it up and use it thus:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
window[name](i);;
}
}
With a namespace, include that:
window["Namespace"]["myfunction"](i);
Note that this is likely a bit of overkill but using a function to make a class object (you can google the makeClass and why it is/could be useful) you can create instances of the object.
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
function makeClass() {
var isInternal;
return function (args) {
if (this instanceof arguments.callee) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
var instance = new arguments.callee(arguments);
isInternal = false;
return instance;
}
};
}
var line = function () {
this.addSpeed = function () {
console.log("works");
};
};
var LineGroup = makeClass();
LineGroup.prototype.init = function (lineNumber) {
this.lAmount = lineNumber?lineNumber:5,
this.lines = [],
this.createLines = function (mything) {
console.log(mything);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i] = new line();
}
},
this.addSpeed = function () {
console.log("here");
this.linesCycle("addSpeed");
},
this.linesCycle = function (callFunction) {
console.log("called:" + callFunction);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i][callFunction]();
}
};
};
var myLines = LineGroup();
myLines.createLines("createlines");
myLines.addSpeed();
//now add a new instance with 3 "lines"
var newLines = LineGroup(3);
newLines.createLines("createlines2")
console.log("addspeed is a:" + typeof newLines.addSpeed);
console.log("line count"+newLines.lAmount );
newLines.addSpeed();

JavaScript - "this" pointing to Window instead of object

I'm facing for the first time OOP in JavaScript and all the troubles that comes with it...
I have this function/Object/class/whatever which has a method mainLoop() that should display some falling text - just like in the movie The Matrix. When I call it though I get undefined variables errors and using the debugger I see that inside mainLoop() this is pointing to Window instead of the object that called the method.
Here's the code:
function Matrix(config) {
return {
//[...lots of other vars...],
drops: [],
lines: [],
//final string to put in the container
str: "",
mainLoop: function(){
var tmp = "";
//randomly create a "character drop"
//(not if there's already a drop)
for(var i = 0; i < this.cols; i++){
if(this.drops[i] == 0 && Math.random() < this.freq){
this.drops[i] = irandom(this.rows) + 1;//new drop
tmp += randomChar();//output drop
}
else tmp += lines[0].charAt(i);
}
this.lines[0] = tmp; // <-------------- ERROR
//update already created drops
tmp = "";
for(var j = 0; j < this.cols; j++){
if(this.drops[j] > 0){
tmp += this.randomChar();
this.drops[j]--;
}
else tmp += " ";
}
this.lines[this.rowIndex] = tmp;
this.rowIndex = (this.rowIndex+1) % this.rows;
//render the entire text
this.str = "";
for(var l in this.lines)
this.str += l + "<br/>";
$(container).html = this.str;
},
start: function(){
for(var i = 0; i < this.cols; i++)
this.drops[i] = 0;
timer = setInterval(this.mainLoop ,this.delay);
},
stop: function(){
clearInterval(this.timer);
},
randomChar: function(){
return this.chars.charAt(irandom(this.chars.length));
},
irandom: function(x){
return Math.floor(Math.random()*x);
}
}
};
And then I call this function like this:
var config = {
container: "#container",
rows: 20,
cols: 20,
delay: 2000
};
var m = Matrix(config);
m.start();
The browser console says:
TypeError: this.lines is undefined
(code comment shows the exact point of the error). Furthermore, the debugger says that, at that point, this points to Window, not to m as I would expect... what's wrong with my reasoning? Thanks in advance for any help.
Alter your start function:
start: function(){
var self = this;
for(var i = 0; i < this.cols; i++)
this.drops[i] = 0;
timer = setInterval(function() {
self.mainLoop();
}, this.delay);
}
this was poiting at window because the scope has changed.
Since JavaScript is prototype-based, maybe (if you haven't already) try doing it following this model:
function Matrix(config) {
this.property = config.firstmember;
this.property2 = config.secondmember;
return function() { console.log('hello world') };
}
Matrix.prototype = {
someMethod: function() {
//do something
},
start: function() {
//console.log('hello world');
},
stop: function() {
//do something
}
}
var config = {
firstMember: 'foo',
secondMember: 'bar'
}
var m = new Matrix(config);
//console output: "hello world"
/*var m = {
property: 'foo',
property2: 'bar',
____proto___: Matrix: {
someMethod: function() {
//do something
},
start: function() {
//console.log('hello world');
},
stop: function() {
//do something
}
}
}*/
Also, see the answer to this question regarding setInterval.
setInterval callback functions are members of the Window object; therefore, 'this' refers to the window. You will need to pass in a parameter of the current object to the callback that is inside setInterval. See the link above for more details.
If you need a reference to the calling object, I'd suggest passing it down as a parameter to the function.

Why am I getting an empty alert box?

I have js function onsubmit forms
var bCancel = false;
var errors = new Array();
function validateNewsForm(form) {
if (bCancel) {
return true;
} else {
errors = [];
var statusArray = new Array();
statusArray.push(validateRequired(form));
statusArray.push(validateMaxLength(form));
statusArray.push(validateDate(form));
for (status in statusArray) {
if (!status) {
alert(errors.join('\n'));
return false;
}
}
return true;
}
}
validateSmth() functions work fine. But when I input correct data I can't save because get empty alert. I have just one alert message and now that all validate functions gives true( in case correct data)
Why can I get empty alert?
for (status in statusArray) {
if (!status) {
A for in loop gives you keys. For an array these are indices. So you're effectively doing !0, !1, etc, and !0 evaluates to true.
You want a normal for loop:
for(var i = 0; i < statusArray.length; i++) {
if (!statusArray[i]) {
Also, you're using [] and new Array() together. It's best to just use [] everywhere.
because for status = 0 !status will be true.
Modified code:
for (var status = 0; status < statusArray.length; status ++) {
if (!statusArray[status] ) {
alert(errors.join('\n'));
return false;
}
}

Categories

Resources