Функция не видит переменной . JS

347
04 марта 2017, 04:53

Здравствуйте.

В теле документа у меня прописано

<div id="okno_print"></div> 
<script> 
  dir = "subscribe/mdadmin/p_ajax/"; 
 
  function get_users() { 
    document.getElementById("okno_print").innerHTML = "<a href='#' onclick='confirmJS(\"delet\"," + activate_delete_users + ");return false;'>test</a>"; 
  } 
 
  function confirmJS(num = false, funct = false) { 
    alert(dir); //тут нормально 
    funct(num); 
    return false; 
  } 
 
  function activate_delete_users(op_users) { 
    alert(dir); //тут пусто 
  } 
 
  get_users(); 
</script>

Объясните, почему в функции, которая передается в виде аргумента пустая переменная dir ? Спасибо

Answer 1

При собирании строки с html обработчиками событий, нужно быть предельно осторожным.

Для того, чтобы понять, почему работает именно так, нужно разобраться, что вообще происходит в данном примере.

Необходимо определить, какая строка в итоге получается.
Строка

"<a href='#' onclick='confirmJS(\"delet\","+activate_delete_users+");return false;'>test</a>"

Преобразуется в следующую

"<a href="#" onclick="confirmJS('delet',function activate_delete_users(op_users) { alert(dir); });return false;">test</a>"

Таким образом в функцию confirmJS передается не уже определенная функция, а вновь созданная.

При этом, важной особенностью inline обработчиков является то, что они создаются в контексте html элемента, это означает, что this в строке

"<a href="#" onclick="console.log(this);return false;">test</a>"

будет ссылаться на элемент a, по которому кликнули. Кроме этого, все переменные используемые в строке обработчика в первую очередь будут искаться в элементе a.

Если посмотреть свойства элемента a, можно увидеть в них свойство dir наследуемое от HTMLElement.

Значение именно этого свойства и выводится в данном случае.

Исправить поведение можно с помощью нескольких способов:

  1. Не собирать строку вообще, а создавать элементы вручную. Например так:

    var deleteButton = document.createElement('a');
    deleteButton.href = '#';
    deleteButton.textContent = 'Test';
    deleteButton.addEventListener('click', function() {
      confirmJS('delet', activate_delete_users);
      return false;
    });
    document.getElementById("okno_print").appendChild(deleteButton);
    

    Этот вариант позволит избежать всех проблем связанных с собиранием строки.

  2. Не вставлять в строку функцию. Это позволит избежать создание этой функции при каждом клике в контексте элемента. Строка в этом случае будет выглядеть следующим образом (метод из комментария @Igor)

    "<a href='#' onclick='confirmJS(\"delet\", activate_delete_users);return false;'>test</a>"
    

    В этом случае, при создании обработчика будет использована ссылка на существующую функцию activate_delete_users.

  3. Так как в функции используется глобальная переменная, к ней можно получить доступ как к свойству объекта window.

    function activate_delete_users(op_users) {
        alert(window.dir); //тут уже не пусто
    }
    
  4. Переименовать глобальную переменную, например:

    directory = "subscribe/mdadmin/p_ajax/";
    

Пример:

var dir = "subscribe/mdadmin/p_ajax/"; 
var directory = "subscribe/mdadmin/p_ajax/"; 
 
function get_users() { 
  wayFour(); 
  wayThree(); 
  wayTwo(); 
  wayOne(); 
} 
 
function wayOne() { 
  var deleteButton = document.createElement('a'); 
  deleteButton.href = '#'; 
  deleteButton.textContent = 'Way 1'; 
  deleteButton.addEventListener('click', function() { 
    confirmJS('delet', activate_delete_users); 
    return false; 
  }); 
  document.getElementById("okno_print").appendChild(deleteButton); 
} 
 
function wayTwo() { 
  document.getElementById("okno_print").innerHTML += "<a href='#' onclick='confirmJS(\"delet\", activate_delete_users);return false;'>Way 2</a> "; 
} 
 
function wayThree() { 
  document.getElementById("okno_print").innerHTML += "<a href='#' onclick='confirmJS(\"delet\", " + activate_delete_users_way_3 + ");return false;'>Way 3</a> "; 
} 
 
function wayFour() { 
  document.getElementById("okno_print").innerHTML += "<a href='#' onclick='confirmJS(\"delet\", " + activate_delete_users_way_4 + ");return false;'>Way 4</a> "; 
} 
 
function confirmJS(num = false, funct = false) { 
  console.log('confirmJS', dir); 
  funct(num); 
  return false; 
} 
 
function activate_delete_users(op_users) { 
  console.log('activate_delete_users', dir); 
} 
 
function activate_delete_users_way_3(op_users) { 
  console.log("activate_delete_users_way_3", window.dir); //тут уже не пусто 
} 
 
function activate_delete_users_way_4(op_users) { 
  console.log("activate_delete_users_way_4", directory); //тут уже не пусто 
} 
get_users();
<div id="okno_print"></div>

READ ALSO
Передача функции в конструктор [дубликат]

Передача функции в конструктор [дубликат]

На данный вопрос уже ответили:

287
Promise и foreach

Promise и foreach

Вопрос: практикуюсь в JavaScript по одноименной книжке, решил написать запрос на ресурс через Promises, однако они возвращают undefinedВ чем может быть...

268
Закладки на JavaScript

Закладки на JavaScript

Всем доброго пятничного дняКак я писал ранее, я изучаю JavaScript по книге Хавербеке

285