I have some code that I absolutely must implement using goto. For example, I want to write a program like this:
start:
alert("RINSE");
alert("LATHER");
repeat: goto start
Is there a way to do that in Javascript?
Absolutely! There is a project called Summer of Goto that allows you use JavaScript at its fullest potential and will revolutionize the way you can write your code.
This JavaScript preprocessing tool allows you to create a label and then goto it using this syntax:
[lbl] <label-name>
goto <label-name>
For example, the example in the question can be written as follows:
[lbl] start:
alert("LATHER");
alert("RINSE");
[lbl] repeat: goto start;
Note that you are not just limited to simple trivial programs like an endless LATHER RINSE repeat cycle—the possibilities afforded by goto are endless and you can even make a Hello, world! message to the JavaScript console 538 times, like this:
var i = 0;
[lbl] start:
console.log("Hello, world!");
i++;
if(i < 538) goto start;
You can read more about how goto is implemented, but basically, it does some JavaScript preprocessing that takes advantage of the fact that you can simulate a goto with a labelled while loop. So, when you write the "Hello, world!" program above, it gets translated to something like this:
var i = 0;
start: while(true) {
console.log("Hello, world!");
i++;
if(i < 538) continue start;
break;
}
There are some limitations to this preprocessing process, because while loops cannot stretch across multiple functions or blocks. That's not a big deal, though—I'm sure the benefits of being able to take advantage of goto in JavaScript will absolutely overwhelm you.
All above link that lead to goto.js library is ALL DEAD, here is links needed:
goto.js (uncompressed) --- parseScripts.js (uncompressed)
From Goto.js:
No. They did not include that in ECMAScript:
ECMAScript has no goto statement.
In classic JavaScript you need to use do-while loops to achieve this type of code. I presume you are maybe generating code for some other thing.
The way to do it, like for backending bytecode to JavaScript is to wrap every label target in a "labelled" do-while.
LABEL1: do {
x = x + 2;
...
// JUMP TO THE END OF THE DO-WHILE - A FORWARDS GOTO
if (x < 100) break LABEL1;
// JUMP TO THE START OF THE DO WHILE - A BACKWARDS GOTO...
if (x < 100) continue LABEL1;
} while(0);
Every labelled do-while loop you use like this actually creates the two label points for the one label. One at the the top and one at the end of the loop. Jumping back uses continue and jumping forwards uses break.
// NORMAL CODE
MYLOOP:
DoStuff();
x = x + 1;
if (x > 100) goto DONE_LOOP;
GOTO MYLOOP;
// JAVASCRIPT STYLE
MYLOOP: do {
DoStuff();
x = x + 1;
if (x > 100) break MYLOOP;
continue MYLOOP;// Not necessary since you can just put do {} while (1) but it illustrates
} while (0)
Unfortunately there is no other way to do it.
Normal Example Code:
while (x < 10 && Ok) {
z = 0;
while (z < 10) {
if (!DoStuff()) {
Ok = FALSE;
break;
}
z++;
}
x++;
}
So say the code gets encoded to bytecodes so now you must put the bytecodes into JavaScript to simulate your backend for some purpose.
JavaScript style:
LOOP1: do {
if (x >= 10) break LOOP1;
if (!Ok) break LOOP1;
z = 0;
LOOP2: do {
if (z >= 10) break LOOP2;
if (!DoStuff()) {
Ok = FALSE;
break LOOP2;
}
z++;
} while (1);// Note While (1) I can just skip saying continue LOOP2!
x++;
continue LOOP1;// Again can skip this line and just say do {} while (1)
} while(0)
So using this technique does the job fine for simple purposes. Other than that not much else you can do.
For normal Javacript you should not need to use goto ever, so you should probably avoid this technique here unless you are specificaly translating other style code to run on JavaScript. I assume that is how they get the Linux kernel to boot in JavaScript for example.
NOTE! This is all naive explanation. For proper Js backend of bytecodes also consider examining the loops before outputting the code. Many simple while loops can be detected as such and then you can rather use loops instead of goto.
Actually, I see that ECMAScript (JavaScript) DOES INDEED have a goto statement. However, the JavaScript goto has two flavors!
The two JavaScript flavors of goto are called labeled continue and labeled break. There is no keyword "goto" in JavaScript. The goto is accomplished in JavaScript using the break and continue keywords.
And this is more or less explicitly stated on the w3schools website here http://www.w3schools.com/js/js_switch.asp.
I find the documentation of the labeled continue and labeled break somewhat awkwardly expressed.
The difference between the labeled continue and labeled break is where they may be used. The labeled continue can only be used inside a while loop. See w3schools for some more information.
===========
Another approach that will work is to have a giant while statement with a giant switch statement inside:
while (true)
{
switch (goto_variable)
{
case 1:
// some code
goto_variable = 2
break;
case 2:
goto_variable = 5 // case in etc. below
break;
case 3:
goto_variable = 1
break;
etc. ...
}
}
This is an old question, but since JavaScript is a moving target - it is possible in ES6 on implementation that support proper tail calls. On implementations with support for proper tail calls, you can have an unbounded number of active tail calls (i.e. tail calls doesn't "grow the stack").
A goto can be thought of as a tail call with no parameters.
The example:
start: alert("RINSE");
alert("LATHER");
goto start
can be written as
function start() { alert("RINSE");
alert("LATHER");
return start() }
Here the call to start is in tail position, so there will be no stack overflows.
Here is a more complex example:
label1: A
B
if C goto label3
D
label3: E
goto label1
First, we split the source up into blocks. Each label indicates the start of a new block.
Block1
label1: A
B
if C goto label3
D
Block2
label3: E
goto label1
We need to bind the blocks together using gotos.
In the example the block E follows D, so we add a goto label3 after D.
Block1
label1: A
B
if C goto label2
D
goto label2
Block2
label2: E
goto label1
Now each block becomes a function and each goto becomes a tail call.
function label1() {
A
B
if C then return( label2() )
D
return( label2() )
}
function label2() {
E
return( label1() )
}
To start the program, use label1().
The rewrite is purely mechanical and can thus be done with a macro system such as sweet.js if need be.
const
start = 0,
more = 1,
pass = 2,
loop = 3,
skip = 4,
done = 5;
var label = start;
while (true){
var goTo = null;
switch (label){
case start:
console.log('start');
case more:
console.log('more');
case pass:
console.log('pass');
case loop:
console.log('loop');
goTo = pass; break;
case skip:
console.log('skip');
case done:
console.log('done');
}
if (goTo == null) break;
label = goTo;
}
Sure, using the switch construct you can simulate goto in JavaScript. Unfortunately, the language doesn't provide goto, but this is a good enough of a replacement.
let counter = 10
function goto(newValue) {
counter = newValue
}
while (true) {
switch (counter) {
case 10: alert("RINSE")
case 20: alert("LATHER")
case 30: goto(10); break
}
}
How about a for loop? Repeat as many times as you like. Or a while loop, repeat until a condition is met. There are control structures that will let you repeat code. I remember GOTO in Basic... it made such bad code! Modern programming languages give you better options that you can actually maintain.
There is a way this can be done, but it needs to be planned carefully.
Take for example the following QBASIC program:
1 A = 1; B = 10;
10 print "A = ",A;
20 IF (A < B) THEN A = A + 1; GOTO 10
30 PRINT "That's the end."
Then create your JavaScript to initialize all variables first, followed by making an initial function call to start the ball rolling (we execute this initial function call at the end), and set up functions for every set of lines that you know will be executed in the one unit.
Follow this with the initial function call...
var a, b;
function fa(){
a = 1;
b = 10;
fb();
}
function fb(){
document.write("a = "+ a + "<br>");
fc();
}
function fc(){
if(a<b){
a++;
fb();
return;
}
else
{
document.write("That's the end.<br>");
}
}
fa();
The result in this instance is:
a = 1
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10
That's the end.
Generally, I'd prefer not using GoTo for bad readability. To me, it's a bad excuse for programming simple iterative functions instead of having to program recursive functions, or even better (if things like a Stack Overflow is feared), their true iterative alternatives (which may sometimes be complex).
Something like this would do:
while(true) {
alert("RINSE");
alert("LATHER");
}
That right there is an infinite loop. The expression ("true") inside the parantheses of the while clause is what the Javascript engine will check for - and if the expression is true, it'll keep the loop running. Writing "true" here always evaluates to true, hence an infinite loop.
You can simple use a function:
function hello() {
alert("RINSE");
alert("LATHER");
hello();
}
To achieve goto-like functionality while keeping the call stack clean, I am using this method:
// in other languages:
// tag1:
// doSomething();
// tag2:
// doMoreThings();
// if (someCondition) goto tag1;
// if (otherCondition) goto tag2;
function tag1() {
doSomething();
setTimeout(tag2, 0); // optional, alternatively just tag2();
}
function tag2() {
doMoreThings();
if (someCondition) {
setTimeout(tag1, 0); // those 2 lines
return; // imitate goto
}
if (otherCondition) {
setTimeout(tag2, 0); // those 2 lines
return; // imitate goto
}
setTimeout(tag3, 0); // optional, alternatively just tag3();
}
// ...
Please note that this code is slow since the function calls are added to timeouts queue, which is evaluated later, in browser's update loop.
Please also note that you can pass arguments (using setTimeout(func, 0, arg1, args...) in browser newer than IE9, or setTimeout(function(){func(arg1, args...)}, 0) in older browsers.
AFAIK, you shouldn't ever run into a case that requires this method unless you need to pause a non-parallelable loop in an environment without async/await support.
// example of goto in javascript:
var i, j;
loop_1:
for (i = 0; i < 3; i++) { //The first for statement is labeled "loop_1"
loop_2:
for (j = 0; j < 3; j++) { //The second for statement is labeled "loop_2"
if (i === 1 && j === 1) {
continue loop_1;
}
console.log('i = ' + i + ', j = ' + j);
}
}
You should probably read some JS tutorials like this one.
Not sure if goto exists in JS at all, but, either way, it encourages bad coding style and should be avoided.
You could do:
while ( some_condition ){
alert('RINSE');
alert('LATHER');
}
goto begin and end of all parents closures
var foo=false;
var loop1=true;
LABEL1: do {var LABEL1GOTO=false;
console.log("here be 2 times");
if (foo==false){
foo=true;
LABEL1GOTO=true;continue LABEL1;// goto up
}else{
break LABEL1; //goto down
}
console.log("newer go here");
} while(LABEL1GOTO);
Another alternative way to achieve the same is to use the tail calls. But, we don’t have anything like that in JavaScript.
So generally, the goto is accomplished in JS using the below two keywords.
break and
continue,
reference: Goto Statement in JavaScript
Here is an example:
var number = 0;
start_position: while(true) {
document.write("Anything you want to print");
number++;
if(number < 100) continue start_position;
break;
}
Related
I have a function -- let's call it test(arg1,arg2), called from program1, which does a number of things and is working correctly. Within test there is a loop:
for(j=1;j<=top;j++) {
stuff happens based on j
}
I would like to call test(arg1,arg2) from a different program, say program2. Everything about test is the same for these two programs except the for loop. For program2 I need that loop to be
for(j=2;j<=top;j+=2) {
stuff happens based on j
}
Otherwise everything else is exactly the same.
The second argument, arg2 tells us whether the script was called from program1 or program2. But I can't figure out how to write a variable "for" statement. I tried an if statement based on arg2
var jstart = 1 or 2
var jincr = '++' or '+=2'
and then wrote the loop as
for(j=jstart;j<=top;j jincr) {
This did not work, although it is an approach that works in other languages.
Can someone suggest I way I can do this without writing an entirely separate script for the two cases?
As simple as that
jstart = 1 // or 2
jincr = 1 // or 2;
for(j=jstart;j<=top;j += jincr) {
The most reusable way would be to put your loop in a function that accepts increment as an argument:
function doStuff (inc) {
for(var j = inc; j <= top; j += inc) {
// stuff happens based on j
}
}
// Program 1
doStuff(1)
// Program 2
doStuff(2)
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I am working on a WordPress plugin. One of its features involves hiding and revealing segments of text by class using <span>.
This functionality works, but I have been hoping to enhance it by having the segments of text reveal one letter at a time (quickly of course) as though they were being typed out very quickly, rather than all at once in large chunks.
I know there are animations out there for this kind of thing ... and perhaps that would be a better solution, but I've been trying to keep it. But the functionality is not really graphic or "animation" oriented; my intent is more just to make a text-based feature look prettier.
I've gotten the portion of the code that builds each segment of text character by character, but I'm trying to insert a very short (5-10ms) delay between each character so that the effect is actually visible. I simply cannot get the setTimeout function to work; can anyone please give me some suggestions?
For simplicity I'm just including the segment of the text that does this; let me know if more context is needed. The following is the FOR loop that goes through every element of an array called cols[] and reveals each element in the array by character. This code works but the delay is never observed.
numberofSnippets = the size of the array cols[]
for (c = 0; c < numberofSnippets; c++)
{
h=0;
currentshown = '';
snippet = cols[c].textContent;
sniplength = snippet.length;
(function addNextCharacter()
{
onecharacter = snippet.charAt(h);
currentshown = currentshown.concat(onecharacter);
cols[c].textContent = currentshown;
h=h+1;
if (h < sniplength) {window.setTimeout(addNextCharacter, 200); }
})();*/
}
}
}
There were a few oddities in your code that was preventing the setTimeout from performing as expected, mostly due to the closure reusing variables within the loop due to the fact that the loop isn't going to wait for the IIFE to finish recursively executing with a setTimeout. I solved that by moving those variables to parameters passed to addNextCharacter.
var cols = document.getElementsByClassName('foo');
var numberofSnippets = cols.length;
for (var c = 0; c < numberofSnippets; c++) {
(function addNextCharacter(h, c, snippet, sniplength, currentshown) {
var onecharacter = snippet.charAt(h);
currentshown = currentshown.concat(onecharacter);
cols[c].textContent = currentshown;
h = h + 1;
if (h < sniplength) {
setTimeout(function () {
addNextCharacter(h, c, snippet, sniplength, currentshown);
}, 10);
}
})(0, c, cols[c].textContent, cols[c].textContent.length, '');
}
<div class="foo">Apple</div>
<div class="foo">Banana</div>
<div class="foo">Orange</div>
<p class="foo">There were a few oddities in your code that was preventing the setTimeout from performing as expected, mostly due to the closure reusing variables within the loop due to the fact that the loop isn't going to wait for the IIFE to finish recursively executing with a setTimeout. I solved that by moving those variables to parameters passed to addNextCharacter.</p>
And here's the obligatory .forEach version which avoids needing to pass the variables around as parameters.
var cols = document.getElementsByClassName('foo');
var numberofSnippets = cols.length;
[].forEach.call(cols, function(el) {
var snippet = el.textContent;
var sniplength = snippet.length;
var currentshown = '';
(function addNextCharacter(h) {
var onecharacter = snippet.charAt(h);
currentshown = currentshown.concat(onecharacter);
el.textContent = currentshown;
h = h + 1;
if (h < sniplength) {
setTimeout(function() {
addNextCharacter(h);
}, 1000);
}
})(0);
});
Well, one issue is that you're setting your timeout to 0, which means, effectively 'next tick'. If you want a 5 second delay, for example, you need to put 5000 in there as the second param.
I am creating a simple program that should utilize the bubble sort algorithm to sort a list of numbers in ascending order.
Just for testing purposes I have added the line alert(unsortedNumbers);and as you can see if you run it, the numbers do not change order no matter how many passes the algorithm does.
The program seems to be stuck in an infinite loop, as 'Another pass' is printed to the console repeatedly. As instructed by this line console.log("Another pass");
As with the bubble sort algorithm, once it does not have to swap any terms on a certain pass, we know this is the sorted list, I have created the variable swapped, however it looks like this is always 1. I think this may be caused by the swapArrayElements() function not swapping the terms.
Why is the function not swapping the index of the terms within the array?
(Code does't seem to run properly on SO's code snippet tool, may have to copy into notepad document)
function main(){
var unsortedNumbers =[7,8,13,1,6,9,43,80]; //Declares unsorted numbers array
alert(unsortedNumbers);
var swapped = 0;
var len = unsortedNumbers.length;
function swapArrayElements(index_a, index_b) { //swaps swapArrayElements[i] with swapArrayElements[ii]
var temp = unsortedNumbers[index_a];
unsortedNumbers[index_a] = unsortedNumbers[index_b];
unsortedNumbers[index_b] = temp;
}
function finish(){
alert(unsortedNumbers);
}
function mainBody(){
for(var i =0;i<len;i++){
var ii =(i+1);
if (unsortedNumbers[i]>unsortedNumbers[ii]){
console.log("Swap elements");
swapArrayElements(i,ii);
swapped=1; // Variable 'swapped' used to check whether or not a swap has been made in each pass
}
if (ii = len){
if (swapped = 1){ // if a swap has been made, runs the main body again
console.log("Another pass");
alert(unsortedNumbers); //Added for debugging
swapped=0;
mainBody();
}else{
console.log("Finish");
finish();
}
}
}
}
mainBody();
}
<head>
</head>
<body onload="main()">
</body>
You have an error in your code:
if (ii = len) {
and also
if (swapped = 1){
it should be double equal
Invalid condition check causing infinite loop:
if (ii = len) & if (swapped = 1) should have == or === operator. This is causing infinity loop.
NOTE: Your code is not appropriate as per the best practices to avoid global variables. You should not use global variables and try
passing variables and returning them back after processing.
Refer this for avoiding globals.
Recently began studying Javascript, trying to read out of Javascript: The Definitive Guide and Eloquent Javascript, while going off on my own to experiment with things in order to really etch them in my memory. I thought a good way to get my head around arithmetic operations and conditional statements, I'd build a series of little games based around each Math operator, and began with addition.
function beginAdditionChallenge() {
var x = Math.ceiling(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
else {
alert("Fail.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
You can see the whole thing thus far on JSFiddle, here. The idea is that clicking the button generates a random number between 1 and 100, displays it to the user, then prompts them to provide two addends, giving them 3 attempts. If the sum of these addends is equal to the RNG number, it congratulates the user and ends the program. If they do not provide suitable addends, the loop prompts them to try again, until they've hit 3 attempts, at which point the program snarks at them and ends.
I know the event listener is not the failure point here, as when I change beginAdditionChallenge to simply display a test alert, it works, but I don't know what exactly is wrong with the loop I've created.
You did it correctly. However, Math.ceiling isn't a function and should be Math.ceil. In addition, your code (in jsfiddle) should be set to wrap in head. Why? Because right now you call initChallenge when the page loads. However, in your jsfiddle example, the code runs onLoad so the load event never gets called. Essentially, you're adding a load event after the page has loaded.
http://jsfiddle.net/rNn32/
Edit: In addition, you have a for loop that goes up to three. Therefore
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
should be
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
because when i === 2, the user's last chance has ended.
Everything is fine. Just change:-
var x = Math.ceiling(Math.random()*100);
to:-
var x = Math.ceil(Math.random()*100);
This question already has answers here:
Why does this append only work if I console log a bad variable
(2 answers)
Closed 9 years ago.
I am relatively new with jquery, and am trying to change an up and down arrow on a js accordion on each click, unfortunately, I have run into an error where it only works if I console.log a bad variable. Does anyone have any guidance as to what I might be doing wrong when I onclick="embiggen(1)" for example if its accordion id one?
There are some other issues surrounding the html, but specifically why is this only working if I console.log;?
function arrowup(id){
$('#downarrow'+id).remove();
$('#dropdown'+id).append('</a>');
$('#dropdown'+id).append('<i id="uparrow'+ id +'" class="icon-1 icon-chevron-up">');
}
function arrowdown(id){
$('#uparrow'+id).remove();
$('#dropdown'+id).append('</a>');
$('#dropdown'+id).append('<i id="downarrow'+ id +'" class="icon-1 icon-chevron-down">');
}
//Switches the arrows
function embiggen(id){
var up = $('#uparrow'+id).length;
if (up == 1){
arrowdown(id);
console.log(i see you);
}
var down = $('#downarrow'+id).length;
if (down == 1){
arrowup(id);
}
}
The bad console.log() makes it "work" because the error breaks the script execution before entering the second if statement.
Fixing the real issue
down == 1 is always true. You should use an else statement:
if ($('#uparrow'+id).length){
arrowdown(id);
} else if ($('#downarrow'+id).length){
arrowup(id);
}
Understanding it
down == 1 is always true independently of up == 1. Here's your logic explained in pseudo-code in both scenarios:
var up = 1, down = 0;
if (up) { down = 1; up = 0; } //enters this block, down now is 1
if (down) { down = 0; up = 1; } //enters this block as down == 1
var up = 0, down = 1;
if (up) { down = 1; up = 0; } //doesn't enter this block
if (down) { down = 0; up = 1; } //enters this block as down == 1
You just have put an else in there so the execution flow does not enter the second if statement in case the first one succeeds.
if (up) {}
else if (down) {}
Truthy/Falsy values
To explain why I'm using .length isolated inside the conditional statement: in JavaScript, the number 0 is a falsy value and 1 is truthy, hence these can be used directly inside the if statement and it will be interpreted based on the internal ToBoolean algorithm logic. Obviously you can == 1 if you feel like, that's more clear though slightly redundant.
A possibly simpler way around
Going a little off-topic, but your goal can most likely be achieved in an easier way. I may be oversimplifying your logic, but depending on your intents you may just toggle between those two classes:
function embiggen(id) {
$('#arrow'+id).toggleClass('icon-chevron-up icon-chevron-down');
}
Then, you'd no longer have to create a new #downarrow/#uparrow element each time the function is called. If said arrow has JS behavior attached, you can check which logic to execute through an if statement using hasClass().
It works because when an error occurs, JavaScript skips the rest of your function body.
The problem in your case is that the function arrowdown() creates #downarrow+id, making the next condition truthy and calling the function arrowup().
You either need an alternative branch, using Fabricio's answer, or return immediately after making changes to the DOM that would otherwise change the state:
function embiggen(id) {
if ($('#uparrow'+id).length) {
return arrowdown(id);
}
if ($('#downarrow'+id).length) {
return arrowup(id);
}
// ehm, something else happened?
}