Почему JSON.stringify теряет часть объекта?
form.img заполняется асинхронно в reader.onload, поэтому в момент вызова JSON.stringify его может не быть
Решил проблему ;)
Проблема была в том, что ридер файла работает в асинхроне, как и сказал Алексей Тен .
Благодарю всех за помощь!Корректный ответ
Поместил XHR отправку в отдельную функцию и вызываю только когда сработает "onload" у ридера файлов.Листингlet form = {};
document.getElementById('ok').addEventListener('click', () => {
  if(document.getElementById('load_img').files.length > 0) {
    var img = document.getElementById('load_img').files[0];
    var reader = new FileReader();
    reader.readAsDataURL(img);
    reader.onload = function() {
      form.img = encodeURIComponent((reader.result).split(',')[1]);
      form.name = encodeURIComponent(document.getElementById('name').value);
      form.desc = encodeURIComponent(document.getElementById('desc').value);
      send();
    }
  } else {
    form.img = '';
    form.name = encodeURIComponent(document.getElementById('name').value);
    form.desc = encodeURIComponent(document.getElementById('desc').value);
    send();
  }

  console.log(form);
});

function send() {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'https://host/api/?product.create=' + JSON.stringify(form));
  // xhr.send();

  console.log('Form: ' + form);
  console.log(JSON.stringify(form));

  xhr.onreadystatechange = () => {
    if(xhr.readyState == 4 && xhr.status == 200) {
      console.log(xhr.responseText);
      var data = JSON.parse(xhr.responseText);

      if(data.code == 1) {
        alert('Товар успешно создан');
        move('search');
      } else {
        alert('Ошибка! ' + data.text);
        move('search');
      }
    }
  }
}