-1

So I checked a thread on here about global and local variables but didn't really find a solution to my problem. I just want a private or local variable to increment so that a function only fires once. I'll paste what I'm trying to achieve here any help would be much appreciate also please go easy on me I'm brand new to JavaScript. This code works but the variable I seems to be shared between functions.

function phonefun(){
    
    i++;
    console.log(i);
    wage = wage - phone;
    console.log(wage);
    display();

    document.getElementById('phone').style.backgroundColor = "darkgrey";
}

function waterfun(){
    
    i++;
    console.log(i);
    wage = wage - water;
    console.log(wage);
    display();

    document.getElementById('water-aid').style.backgroundColor = "darkgrey";
}
moderategamer
  • 189
  • 2
  • 10
  • what exactly are you trying to archive? – DZDomi Jan 26 '18 at 00:28
  • Put `var` before your assignment of `i`. – alex Jan 26 '18 at 00:28
  • Done that didn't work, should it have? – moderategamer Jan 26 '18 at 00:30
  • Just trying to have a function only fire once like a doonce but from what I understand JS doesn't have that no ? – moderategamer Jan 26 '18 at 00:32
  • why do you need your function to fire once? cant you just invoke it once? it seems to me there is a degree of uncertainty about how many times this function will be invoked, that uncertainty is what needs to be fixed. Please add your complete use-case so we can better help you. – Ahmed Musallam Jan 26 '18 at 00:54
  • @AhmedMusallam the function is called on the click of a button, I want it so you can only press the button once which is what the code I showed does however I have several buttons that I want all to have the same functionality. I could just use a different variable name for each function but that seems silly I should be able to have private variable. I know how to make a private variable now but the problem is if I set the variable to zero within the function then every time I fire the function it will set the variable back to zero and add one which breaks the logic. I will edit the post. – moderategamer Jan 26 '18 at 01:14
  • if you want the button to be clickable once, why not disable the button after it was clicked ? – Ahmed Musallam Jan 26 '18 at 01:20
  • @AhmedMusallam because I didn't know that was an attribute, I do now. Still there should be an easy way to do what I was originally trying to do. – moderategamer Jan 26 '18 at 01:24

5 Answers5

1

you can make a class

function myStuff(){
  this.i = 0,
  this.loanfun = function(){
    this.i++;
    if (this.i == 1) {
        wage = wage - loan;
        console.log(wage);
        display();
        document.getElementById('loan').style.backgroundColor = "darkgrey";
    }
  }
}

var s = new myStuff();
s.loanfun();
s.loanfun();
Andam
  • 2,087
  • 1
  • 8
  • 21
  • Thanks for the reply however the reason I want it to be private is that I want to do this several times for different functions. If it's not private then I just keeps incrementing breaking the statement. I was under the impression I didn't need to declare I as a variable as it defaults to zero. I also assumed that variables inside functions would be private by default but I guess I was wrong about that one. – moderategamer Jan 26 '18 at 00:39
  • @moderategamer you can create a class of it and define i as property – Andam Jan 26 '18 at 00:41
  • @moderategamer All variables should be declared with `var`, `let`, or `const`. If they aren't declared with those words, the variable becomes Global by default. Variables don't default to zero if they aren't explicitly set, the default to `undefined`. And, yes, variables declared inside functions are local to that function. – Scott Marcus Jan 26 '18 at 00:41
  • @ScottMarcus thanks so what you're saying is if I declare the variable I within the function it will be local to that function? Also what does let signify? – moderategamer Jan 26 '18 at 00:52
  • @Andam Thanks what does this. do? – moderategamer Jan 26 '18 at 00:53
  • @moderategamer this explain it in a good way https://stackoverflow.com/questions/1963357/this-inside-function my english is not so good to explain it in my words – Andam Jan 26 '18 at 00:56
  • @Andam Thanks for that. – moderategamer Jan 26 '18 at 01:24
  • @moderategamer Yes, variables declared within a function are always local to that function. `let` allows you to declare "block" scope, which can be smaller than the function, like the `true` branch of an `if` statement, for example. **[Here'e more](https://stackoverflow.com/questions/41496958/this-does-not-work-properly-in-another-event-im-clueless-as-to-why/41496969#41496969)** on what `this` is. – Scott Marcus Jan 26 '18 at 02:01
  • @ScottMarcus thanks that makes sense appreciate the help. – moderategamer Jan 26 '18 at 03:07
1

To do what you want, you need a variable with a higher scope than the function so that the value can persist between function calls. A local variable will be garbage collected as the function returns and so, your counter would be lost.

var counter = 0;  // This variable exists in a higher scope than the function

function loanfun(){
    counter++;
    if (counter == 1) {
      console.log("function has run " + counter + " times.");
    }
}

loanfun();  // Will run
loanfun();  // Won't run
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • Thanks so basically I have to make a new variable for every function so that they don't conflict. I wasn't really thinking about the fact that it would be set back to zero every time I called the function that's annoying. Thanks for the reply. – moderategamer Jan 26 '18 at 01:27
  • @moderategamer There are a variety of ways to structure the code, but in the end, you will need separate variables to track different functions. – Scott Marcus Jan 26 '18 at 01:50
  • Thanks for the tips – moderategamer Jan 26 '18 at 01:54
  • @moderategamer You're welcome. Don't forget to up vote all helpful answers and mark one as "the" answer if your question has been answered. – Scott Marcus Jan 26 '18 at 01:57
1

You could try namespacing within an object:

var PageModule = {
    count: 0,

    loadfun: function (wage, loan) {
        PageModule.count += 1;

        if (PageModule.count === 1) {
            console.log('execute!');
            wage = wage - loan;
            console.log(wage);
            display();

            document.getElementById('loan').style.backgroundColor = "darkgrey";
        }

    }
};

PageModule.loadfun();
PageModule.loadfun();
PageModule.loadfun();

// if you want to attach the method to a button
document.getElementById('my-btn-id').addEventListener('click', PageModule.loadfun);

Alternatively, you could use the following approach:

function myclickhandler () {
    // do whatever you want here ...

    //remove handler from button, so that the next button clicks will not do anything
    document.getElementById('my-btn-id').removeEventListener('click', myclickhandler);
}

// attach the method to a button
document.getElementById('my-btn-id').addEventListener('click', myclickhandler);
Talha
  • 807
  • 9
  • 13
  • Thanks for the reply, I'm assuming that this is probably the solution but I simply don't understand it. What would I call for the onclick event on my button? Sorry I'm very new to JavaScript? – moderategamer Jan 26 '18 at 01:10
  • You would just attach `PageModule.loadfun` to the click event on the button. I added a code snippet above for this. – Talha Jan 26 '18 at 18:25
  • Also added an alternative approach which remove the click function from the button after it runs once. – Talha Jan 26 '18 at 18:30
  • That makes sense thanks for getting back to me appreciate it. I went for the remove click method. – moderategamer Jan 27 '18 at 23:51
1

...the function is called on the click of a button, I want it so you can only press the button

I think what you want to do is have your event handler unbind from the button after if fires. Thas is much better solution than counting how many times it's been clicked. Check out this link for how to bind and unbind event handlers using "vanilla" JS: https://plainjs.com/javascript/events/binding-and-unbinding-of-event-handlers-12/

In reference to your earlier questions...

  1. A variable created inside of a function is said to be "scoped" to that function, which means that nothing outside of that function can access the variable. However, by initializing your variable without using the var or let keyword (the latter is ES6 syntax), you created an implicit global. This means that you inadvertently made it a global variable when you wanted it to be function-scoped.

  2. Declaring a variable does not automatically assign a value of zero. If you do not assign a value, the value will be undefined.

  3. If you had declared / assigned the variable thusly,var i = 0; or let i = 0; you would have had a properly scoped variable with an initial value of 0. The problem is, each time that function executed, the value would be reset to zero. To get the value to "stick" you would have to create state. You could do that by creating an object with getter and setter methods or by using a closure. However, the unbind solution seems to be the best way to go for what you want to do here.

I hope this helps.

Neil Girardi
  • 4,533
  • 1
  • 28
  • 45
0

Hope that this is what you want to do.But if you want simply to call(invoke) you function once just call and it will be executed only one time.

wage = 10;
loan = 5;
i=0; //this is the global variable
function loanfun(){
    let j = i +1; //j is local variable
    if (j === 1) {
        wage = wage - loan;
        console.log(wage);
        //display();
    
      document.getElementById('loan').style.backgroundColor = "darkgrey";
    }
}
loanfun(); //invoke the function here
<div id="loan">
    hi I am here working as expected
</div>
Firas Omrane
  • 894
  • 1
  • 14
  • 21
  • Thanks for the reply, I'm not fully understanding it though why do I make variable J = I and what makes your variable J private. Also what does let do? I think maybe there's a misunderstanding of what I want to do. Basically I have a button that fires a the function but there are also several more buttons that fire a near duplicate of that function with different math. The problem is that when I fire one function it increments I by one but then when I press another button it also increments that same variable meaning the if statement only checks out once. sorry I'm not very good at explaining. – moderategamer Jan 26 '18 at 00:48
  • @moderategamer I think you should add at least 2 buttons with the code sample so everyone can understand. – Firas Omrane Jan 26 '18 at 00:52