Uncaught TypeError: Cannot read property — что это означает

Допу­стим, вы дела­е­те стра­ни­цу с фор­мой и полем ввода:

<form name="myform">
  <input name="myinput" value="10" />
</form>

Нуж­но, что­бы скрипт нашёл эту фор­му, достал из неё зна­че­ние поля вво­да и вывел его на экран. Вы пише­те скрипт и оформ­ля­е­те его как отдель­ный файл, кото­рый под­клю­ча­е­те в раз­де­ле head:

<script>
  var str = '';
  for(i=0; i < document.myform.elements.length; i++){
     str += document.myform.elements[i].name + '=' + encodeURIComponent(document.myform.elements[i].value) + (i == document.myform.elements.length -1 ? '' : '&');
    }
  alert(str);
</script>

Этот скрипт дол­жен быть пра­виль­ным. При тести­ро­ва­нии внут­ри кон­со­ли он дела­ет имен­но то, что нуж­но. Но после запус­ка скрипт пада­ет с ошибкой:

❌ Uncaught TypeError: Cannot read property

Это озна­ча­ет: «Вы пыта­е­тесь про­чи­тать у объ­ек­та какое-то свой­ство, но я не могу его най­ти, а зна­чит, не могу и про­чи­тать то, чего нет».

Стран­но, ведь вы уве­ре­ны, что у это­го объ­ек­та такое свой­ство точ­но есть, и вы сто раз так уже делали.

Всё так и одно­вре­мен­но не так.

Что делать с ошибкой Uncaught TypeError: Cannot read property

Эта ошиб­ка чаще все­го про­ис­хо­дит, когда вы обра­ща­е­тесь к свой­ствам объ­ек­та рань­ше, чем объ­ект готов:

  • Ско­рее все­го, объ­ект ещё не загрузился.
  • Может быть, этот объ­ект дол­жен появить­ся на стра­ни­це по скрип­ту, кото­рый ещё не выполнился.
  • Допу­ще­на опе­чат­ка в назва­нии объ­ек­та, поэто­му при обра­ще­нии к нему скрипт его не находит.

Наш слу­чай — пер­вый и самый рас­про­стра­нён­ный: мы вызы­ва­ем скрипт в раз­де­ле <head>, но фор­ма у нас ещё не гото­ва — она баналь­но не загру­же­на в доку­мент, поэто­му скрипт не может про­чи­тать свой­ства несу­ще­ству­ю­щей формы.

Что­бы изба­вить­ся от этой ошиб­ки, нуж­но доба­вить в вызов скрип­та атри­бут defer — он заста­вит скрипт подо­ждать, пока стра­ни­ца загру­зит­ся пол­но­стью, вме­сте с формой.

<script defer src="...">

Вто­рой вари­ант — поме­стить вызов скрип­та сра­зу после фор­мы, тогда к момен­ту вызо­ва всё ока­жет­ся на сво­их местах и ошиб­ки не будет. Или вооб­ще в кон­це все­го документа.