Arvind M.
Arvind M.

Reputation: 67

true/false vs int in JavaScript (unexpected behavior)

I'am kind of new to javascript and today I was working on a function that basically toggles a value and displays it as alert but I stumbled across a weird behavior of JavaScript relating to true/false and 0/1.

The following code , when user clicks on toggle anchor link, it doesn't seem to toggle the value and the alert always gives "true" (which i thought should happen):

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>'+ document.body.innerHTML;
function f() {
    this.status = true;
    var btn = document.getElementById("toggle")
    btn.addEventListener("click", () => {
        if (this.status == true) {
             alert(this.status)
            this.status = false;
        } else {
            alert(this.status)
            this.status = true;
        }

     }, false)
}

f()

But if I use 0 and 1 instead of true/false the code works for some reason.

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>' +document.body.innerHTML;

function f() {
    this.status = 1;
    var btn = document.getElementById("toggle")
    btn.addEventListener("click",()=>{
    if(this.status==1){
         alert(this.status)
         this.status = 0;
    }else{
        alert(this.status)
        this.status = 1;
      }

     },false)
 }

 f()

I have no idea what's going on here, Is this because of this pointer i am using in the function or something?.

Upvotes: 2

Views: 221

Answers (4)

Isac
Isac

Reputation: 1874

The problem is that your function f is called without new so the this refers to the window object, which already has astatus property with its own meaning.

You can see this if you print its type:

function f() {
    this.status = true;
    console.log(typeof this.status);
 }

 f()

Note how the result is string instead of the expected boolean.

But if you name it differently:

function f() {
    this.myprop = true;
    console.log(typeof this.myprop);
 }

 f()

It yields the correct type.

So to make it work you need only to change its name. But the if else logic you have to invert the boolean can be turned into a !(not), which simplifies the code a lot:

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>' + document.body.innerHTML;

function f() {
  this.myStatus = true;
  var btn = document.getElementById("toggle");
  
  btn.addEventListener("click", () => {
    this.myStatus = !this.myStatus; //here the value is inverted only with the ! (not)
    console.log(this.myStatus);
  }, false);
}

f();

But using the window object is discouraged, for reasons much like the one you were experiencing, and the myStatus property is still being stored there.

You can improve the solution a bit more:

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>' + document.body.innerHTML;

function f() {
  let myStatus = true;
  var btn = document.getElementById("toggle");
  
  btn.addEventListener("click", () => {
    myStatus = !myStatus; //here the value is inverted only with the ! (not)
    console.log(myStatus);
  }, false);
}

f();

Also, don't forget to finish the statements with the semicolons, i noticed that you had almost none of them.

Upvotes: 4

Matthew
Matthew

Reputation: 667

Other people have posted some good responses, but here's my two cents.

You can initialize a local variable in your function that will initialize a value and then alternate on that value when the button is clicked. Your use of this notation does not seem to be necessary here.

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>'+ document.body.innerHTML;
function f() {
    var status = true;
    var btn = document.getElementById("toggle")
    btn.addEventListener("click", () => {
        if (status === true) {
            alert(status)
            status = false;
        } else {
            alert(status)
            status = true;
        }

     }, false);
}

f();

When using this, always know what you are referring to. As Isac pointed out, your this referred to the document window, which seems to have been an issue.

Codepen:

https://codepen.io/foozie3moons/pen/gGRBxZ?editors=0010

Upvotes: 0

Ben
Ben

Reputation: 5626

Since you're new to JavaScript you probably haven't heard, but you should know when to use === instead of == (hint: always).

In a nutshell, because JavaScript is weakly/un-typed it can be difficult to know if you're actually comparing two of the same thing (numbers) or two different things (number and object):

new Number(10) == 10 // true
new Number(10) === 10 // false

Because:

typeof Number(10) // returns number
typeof 10 // returns number
typeof new Number(10) // returns object

^ Above example from https://coderwall.com/p/bqurhg/why-always-use-in-javascript

Upvotes: 0

zhuravlyov
zhuravlyov

Reputation: 503

document.body.innerHTML = '<a href="#" id="toggle"> toggle </a>'+ document.body.innerHTML;
function f() {
    let status = true;
    let btn = document.getElementById("toggle");
    btn.addEventListener("click", () => {
        if (status === true) {
            alert(status);
            status = false;
        } else {
            alert(status);
            status = true;
        }

    }, false)
}

f();

Upvotes: -1

Related Questions