2013-11-20 3 views
0

Я наткнулся на что-то странное, и я хотел поделиться им с вами, чтобы вы могли помочь моему разочарованию. (мне потребовалось некоторое время, чтобы понять, что не так)Объект контекста контекста javascript необъявленные переменные

Я хотел создать рекурсивную функцию, которая бы отображала дерево как структуру данных на вложенном элементе <ul>.

Структура данных была в таком виде:

var contents = [ 
    { 
     name : 'test', 
     contents : [ 
      { 
       name : 'test > test 1' 
      }, 
      { 
       name : 'test > test 2' 
      }, 
      { 
       name : 'test > test 3' 
      }     
     ] 
    }, 
    { 
     name : 'test 2' 
    }   
]; 

Я добавил свой код на предметном блоке, например:

var dummy = { 
    do : function() { 
     var element = $('<ul>'); 
     dummy.recursive(element, contents); 

     $("#content").append(element); 
    }, 
    recursive : function(element, contents) { 
     for(i = 0; i < contents.length; i++) { 
      var item = contents[i]; 

      var li = $('<li> (' + i + ') ' + item.name + '</li>'); 

      if(item.contents && item.contents.length) { 
       var ul = $('<ul>'); 
       dummy.recursive(ul, item.contents); 

       li.append(ul); 
      } 
      element.append(li); 
     } 
    } 
}; 

Я обнаружил, что переменная i после dummy.recursive побежал на содержимое первого элемента больше не было 0, а вместо 2. Это означает, что хотя i находится в его личном контексте, заменяется рекурсивной функцией.

Я также добавил jsfiddle, чтобы проиллюстрировать эту проблему здесь: http://jsfiddle.net/MWQJC/2/

Проблема заключается в переменной i не объявлена ​​явно делая var i = 0 на начало функции. (Как проиллюстрировано здесь: http://jsfiddle.net/h8gtd/1/)

По-видимому, по умолчанию всякая необъявленная переменная, доступ к которой создается, создается в области объекта. Это так?

+1

Там действительно есть еще один урок, знайте основы, прежде чем начинать делать сложные вещи. Если бы вы прочитали какую-либо книгу на javascript, одна из первых вещей, которую вы узнали бы, это определение областей, переменных дециляций и подъемов, а также использование IIFE. – adeneo

+0

@adeneo Ну, исходя из другого фона разработки, вы неправильно думаете, что JS прост и, как правило, переходит к более сложным вещам. Touche ... – mobius

ответ

2

По умолчанию каждый незаявленный доступ к переменной составляет , созданный в области объектов. Это так?

Номер

Каждый раз доступ (чтения) значение переменного, двигатель JS пытается найти переменную в текущей области, то во внешней рамке текущей области, то внешних объем этой области и т. д., пока вы не найдете глобальную область действия. В этот момент, если переменная все еще не была объявлена, возникает ошибка.

Когда вы задаете (записываете) значение переменной, выполняется тот же процесс, при этом последний шаг отличается. Если переменная не была объявлена ​​даже в глобальной области, тогда в глобальной области будет создана переменная с этим именем.

Ex:

// global scope 
!function() { // scope 1 
    var x; // comment this line to log 7 instead 
    !function() { // scope 2 
    x = 7; 
    }() 
}(); 

console.log(x) // undefined, because it never reached the global scope 

В вашем конкретном примере, вы правы, что проблема заключается в том, что i не была объявлена ​​как переменная в рекурсивной функции, поэтому все вызовы этой рекурсивной функции будут использовать ту же переменную i, определенную в некоторой внешней области или в глобальной области.

EDIT: Я продолжал использовать слово scope, но забыл упомянуть, что в отличие от многих других языков, JavaScript не имеет области блока, но имеет область действия.

1

Вы запрашиваете closure. Это подробно объяснено here.

цитата:

Это замыкание. Функция не должна возвращаться, чтобы быть , называемой замыканием. Простое обращение к переменным за пределами вашего непосредственного лексической области создает закрытие.

function foo(x) { 
    var tmp = 3; 
    return function (y) { 
    alert(x + y + (++tmp)); 
    } 
} 
var bar = foo(2); // bar is now a closure. 
bar(10); 

выше функция будет также предупреждение 16, потому что бар может по-прежнему относятся к х и TMP, даже если он больше не является непосредственно внутри сферы.

Смежные вопросы