Thiago C. S Ventura
Thiago C. S Ventura

Reputation: 2602

Why the private property does not have the same scope?

I am studying module pattern with javascript and the code below is my first try, a list of tasks. I have a small issue with variable's scope.

In one of my public methods I can access the tasks variable, in another one I can't. I will try to give more details.

I have my public method "addItem" which basically does a "push" in an array tasks.push(values); in this moment it works well, my array gets the new data.

But when I try to show the same variable in my other public method "deleteTask", example: console.log('deleteTask: ', tasks);. It returns me "deleteTask: undefined"

In the second code snippet, I am showing, how I access the methods.

Well, basically I am trying to understand, why am I not able to access the private variable in "deleteTask"? And why can I in "addItem"? What the difference? It looks like simple, but I am not getting so far.

var todoModule = (function ($) {
    var tasks = [];

    function doListOfTasks() {
        for(var i=0; i<tasks.length; i++){
            $('<li>', {
                name    : 'liTask',
                id      : 'liTask'+i,
                html    : tasks[i].title + ' - '
            }).appendTo('#listOfTasks');

            $('<input>', {
                type    : 'button',
                name    : 'delTask',
                id      : 'delTask'+i,
                value   : 'Del'
            }).appendTo('#liTask'+i);

            $('#delTask'+i).data('idTask', i);
        }
    }

    function clearListTasks(){
        $('#listOfTasks').html('');
    }

    return { 
        init: function(){
            this.getListTasks();
        },

        getListTasks: doListOfTasks,

        addItem: function( values ) {
            tasks.push(values);
            clearListTasks();
            this.getListTasks();

            console.log('addItem: ', tasks);
        },

        deleteTask: function(item) {
            console.log('deleteTask: ', tasks);

            var tasks = $.grep(tasks, function(value, item) {
                        //console.log('value: ', value);
                        //console.log('item: ', item);
                        return value != item;
                    });

            clearListTasks();
            doListOfTasks();
        }
    };
}(jQuery));

My HTML:

Here I am accessing the public methods through events:

<script type="text/javascript">
    $( document ).ready(function() {
            todoModule.init();

            $( '#btnAdd' ).click(function() {
                todoModule.addItem({
                    title: $('#tarefa').val(),
                    date: '01/01/1999',
                    flag: 0
                });
            });

            $('ul').on('click', 'input', function() {
                var idTask = $('#'+this.id).data('idTask');
                todoModule.deleteTask(idTask);
            });
        });
</script>

I am studying this pattern through this link

Upvotes: 2

Views: 60

Answers (2)

mati
mati

Reputation: 5348

It happens because in the deleteTask method you define a new local variable named tasks, which is undefined (does not have any value assigned) at the moment of usage:

 deleteTask: function(item) {
      console.log('deleteTask: ', tasks);
      var tasks = $.grep(tasks, function(value, item) {
        //console.log('value: ', value);
        //console.log('item: ', item);
         return value != item;
      });
      clearListTasks();
      doListOfTasks();
 }

It doesn't matter if you first use, and then define it - the var definition will override the tasks you intend to use with the local tasks, which has no value assigned yet ( won't have one until the grep execution). I recommend reading about var hoisting in javascript.
You could rename the local tasks variable to quickly fix this problem. However, as Bergi said, you would possibly want to modify the tasks that's outside the function's scope, so avoiding the var keyword would suffice.

Upvotes: 0

Bergi
Bergi

Reputation: 664579

Why can I access the private variable in "addItem"?

That's the default. Variables in higher (enclosing) scopes are accessible to every function defined inside there, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Nested_functions_and_closures.

Why can't I in "deleteTask"?

Because of that line:

    var tasks = $.grep(tasks, …)
//  ^^^

Here you are declaring another variable with the name tasks for the scope of the deleteTask function. It will shadow the other one. Probably you didn't want to do that but overwrite the tasks variable from the upper scope - just omit the var keyword.

Upvotes: 1

Related Questions