В компании Rollbar, которая занимается созданием инструментов для работы с ошибками в программах, решили проанализировать базу из более чем 1000 проектов на JavaScript и найти в них ошибки, которые встречаются чаще всего. В результате они сформировали список из 10 наиболее часто встречающихся ошибок, проанализировали причины их появления и рассказали о том, как их исправлять и избегать. Они полагают, что знакомство с этими ошибками поможет JS-разработчикам писать более качественный код.
Сегодня мы публикуем перевод их исследования.
Методика анализа
В наши дни данные — это всё, поэтому мы нашли, проанализировали и проранжировали ошибки, которые чаще всего встречаются в JavaScript-проектах. А именно, были собраны сведения об ошибках по каждому проекту, после чего было подсчитано количество ошибок каждого вида. Ошибки группировались по их контрольной сумме, методику вычисления которой можно найти здесь. При таком подходе, если, например, в одном проекте обнаружена некая ошибка, которая после этого найдена где-то ещё, такие ошибки группируют. Это позволяет, после анализа всех участвующих в исследовании проектов, получить краткую сводку по ошибкам, а не нечто вроде огромного лог-файла, с которым неудобно работать.
В ходе исследования особое внимание уделялось наиболее часто встречающимся ошибкам. Для того чтобы такие ошибки отобрать, их ранжировали по количеству проектов разных компаний, в которых они встречаются. Если бы в этот рейтинг входило лишь общее число появлений некоей ошибки, то ошибки, характерные для какого-нибудь очень крупного проекта, но редко встречающиеся в других проектах, исказили бы результаты.
Вот десять ошибок, которые были отобраны по результатам исследования. Они отсортированы по количеству проектов, в которых они встречаются.
Ошибки, которые встречаются в JS-проектах чаще всего
Названия ошибок представляют собой сокращённый вариант сообщения об ошибке, которое выдаёт система. Опора на системные сообщения позволяет легко идентифицировать ошибки при их возникновении. Сейчас мы проанализируем каждую из них, расскажем о том, что их вызывает, и о том, как с ними бороться.
1. Uncaught TypeError: Cannot read property
Если вы пишете программы на JavaScript, то вы, вероятно, встречались с этой ошибкой гораздо чаще, чем вам того хотелось бы. Подобная ошибка возникает, например, в Google Chrome при попытке прочитать свойство или вызвать метод неопределённой переменной, то есть той, которая имеет значение undefined
. Увидеть эту ошибку в действии можно с помощью консоли инструментов разработчика Chrome.
Ошибка Cannot read property
Эта ошибка может возникнуть по многим причинам, но чаще всего её вызывает неправильная инициализация состояния при рендеринге элемента пользовательского интерфейса. Взглянем на пример того, как подобное может произойти в реальном приложении. Тут мы используем React, но та же ошибка инициализации характерна для Angular, Vue и для любых других фреймворков.
class Quiz extends Component {
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
Тут надо обратить внимание на две важные вещи:
- В самом начале состояние компонента (то есть —
this.state
) представлено значениемundefined
. - При асинхронной загрузке данных компонент будет выведен как минимум один раз до того, как данные будут загружены, вне зависимости от того, будет ли это выполнено в
componentWillMount
или вcomponentDidMount
. Когда элементQuiz
выводится в первый раз, вthis.state.items
записаноundefined
. Это, в свою очередь, означает, чтоitemList
получает элементы, которые так же представлены значениемundefined
. Как результат, мы видим в консоли следующую ошибку:"Uncaught TypeError: Cannot read property ‘map’ of undefined"
.
Эту ошибку исправить несложно. Проще всего инициализировать состояние в конструкторе подходящими значениями по умолчанию.
class Quiz extends Component {
// Добавляем это:
constructor(props) {
super(props);
// Инициализируем состояние и задаём значения элементов по умолчанию
this.state = {
items: []
};
}
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
Код вашего приложения будет выглядеть иначе, но мы надеемся, что теперь вы знаете, как исправить эту ошибку в своём проекте и как избежать её появления. Если то, о чём шла речь, вам не подходит — возможно, вам поможет разбор следующих ошибок.
2. TypeError: ‘undefined’ is not an object (evaluating…
Эта ошибка возникает в браузере Safari при попытке прочесть свойство или вызвать метод неопределённого объекта. Взглянуть на эту ошибку можно с помощью консоли инструментов разработчика Safari. На самом деле, тут перед нами та же самая проблема, которую мы разбирали выше для Chrome, но в Safari она приводит к другому сообщению об ошибке.
Ошибка ‘undefined’ is not an object
Исправлять эту ошибку надо так же, как в предыдущем примере.
3. TypeError: null is not an object (evaluating
Эта ошибка возникает в Safari при попытке обратиться к методу или свойству переменной, представленной значением null
. Вот как это выглядит в консоли разработчика Safari.
Ошибка TypeError: null is not an object
Напомним, что в JavaScript null
и undefined
— это не одно и то же, именно поэтому мы видим разные сообщения об ошибках. Смысл значения undefined
, записанного в переменную, говорит о том, что переменной не назначено никакого значения, а null
указывает на пустое значение. Для того чтобы убедиться в том, что null
не равно undefined
, можно сравнить их с использованием оператора строгого равенства:
Сравнение undefined и null с помощью операторов нестрогого и строгого равенства
Одна из причин возникновения подобной ошибки в реальных приложениях заключается в попытке использования элемента DOM в JavaScript до загрузки элемента. Происходит это из-за того, что DOM API возвращает null
для ссылок на пустые объекты.
Любой JS-код, который работает с элементами DOM, должен выполняться после создания элементов DOM. Интерпретация JS-кода производится сверху вниз по мере появления его в HTML-документе. Поэтому если тег <script>
с программой окажется перед кодом, описывающим элементы DOM, программа будет выполнена в ходе разбора страницы до его завершения. Эта ошибка проявится, если элемент DOM, к которому обращаются из скрипта, не был создан до загрузки этого скрипта.
В следующем примере мы можем исправить проблему, добавив в код прослушиватель событий, который оповестит нас о том, что страница полностью загружена. После срабатывания обработчика события, добавленного с помощью addEventListener
, метод init()
сможет правильно работать с элементами DOM.
<script>
function init() {
var myButton = document.getElementById("myButton");
var myTextfield = document.getElementById("myTextfield");
myButton.onclick = function() {
var userName = myTextfield.value;
}
}
document.addEventListener('readystatechange', function() {
if (document.readyState === "complete") {
init();
}
});
</script>
<form>
<input type="text" id="myTextfield" placeholder="Type your name" />
<input type="button" id="myButton" value="Go" />
</form>
4. (unknown): Script error
Эта ошибка возникает в том случае, когда неперехваченная ошибка JavaScript пересекает границы доменов при нарушении политики кросс-доменных ограничений. Например, если ваш JS-код размещён на CDN-ресурсе, в сообщении о любой неперехваченной ошибке (то есть, об ошибке, которая не перехвачена в блоке try-catch
и дошла до обработчика window.onerror
) будет указано Script error
, а не полезная для целей устранения этой ошибки информация. Это — один из браузерных механизмов безопасности, направленный на предотвращение передачи данных между фрагментами кода, источниками которого являются разные домены, и которым в обычных условиях запрещено обмениваться информацией.
Вот последовательность действий, которая поможет увидеть эту ошибку.
1. Отправка заголовка Access-Control-Allow-Origin
.
Установка заголовка Access-Control-Allow-Origin
в состояние *
указывает на то, что к ресурсу можно получить доступ из любого домена.
Знак звёздочки можно, при необходимости, заменить на конкретный домен, например так: Access-Control-Allow-Origin: www.example.com
. Однако поддержка нескольких доменов — дело довольно сложное. Такая поддержка может не стоить затраченных на её обеспечение усилий, если вы используете CDN, из-за возможного возникновения проблем с кэшированием. Подробности об этом можно посмотреть здесь.
Вот примеры установки этого заголовка в различных окружениях.
Apache
В папке, из которой будут загружаться ваши JavaScript-файлы, создайте файл .htaccess
со следующим содержимым:
Header add Access-Control-Allow-Origin "*"
Nginx
Добавьте директиву add_header
к блоку location
, который отвечает за обслуживание ваших JS-файлов:
location ~ ^/assets/ {
add_header Access-Control-Allow-Origin *;
}
HAProxy
Добавьте следующую настройку к параметрам системы, ответственной за поддержку JS-файлов:
rspadd Access-Control-Allow-Origin: *
2. Установите crossorigin="anonymous"
в теге <script>
.
В вашем HTML-файле для каждого из скриптов, для которого установлен заголовок Access-Control-Allow-Origin
, установите crossorigin="anonymous"
в теге <script>
. Перед добавлением свойства crossorigin
к тегу <script>
проверьте отправку заголовка для файла скрипта. В Firefox, если атрибут crossorigin
присутствует, а заголовок Access-Control-Allow-Origin
— нет, скрипт выполнен не будет.
5. TypeError: Object doesn’t support property
Эта ошибка возникает в IE при попытке вызова неопределённого метода. Увидеть эту ошибку можно в консоли разработчика IE.
Ошибка Object doesn’t support property
Эта ошибка эквивалентна ошибке "TypeError: ‘undefined’ is not a function"
, которая возникает в Chrome. Обращаем ваше внимание на то, что речь идёт об одной и той же логической ошибке, о которой различные браузеры сообщают по-разному.
Это — обычная для IE проблема, возникающая в веб-приложениях, которые используют возможности пространств имён JavaScript. Когда возникает эта ошибка, то в 99.9% случаев её причиной является неспособность IE привязывать методы, расположенные в текущем пространстве имён, к ключевому слову this
. Например, предположим, что имеется объект Rollbar
с методом isAwesome
. Обычно, находясь в пределах этого объекта, метод isAwesome
можно вызвать так:
this.isAwesome();
Chrome, Firefox и Opera нормально воспримут такую команду. IE же её не поймёт. Таким образом, лучше всего, при использовании подобных конструкций, всегда предварять имя метода именем объекта (пространства имён), в котором он определён:
Rollbar.isAwesome();
6. TypeError: ‘undefined’ is not a function
Эта ошибка возникает в Chrome при попытке вызова неопределённой функции. Взглянуть на эту ошибку можно в консоли инструментов разработчика Chrome и в аналогичной консоли Firefox.
Ошибка TypeError: ‘undefined’ is not a function
Так как подходы к программированию на JavaScript и шаблоны проектирования постоянно усложняются, наблюдается и соответствующий рост числа ситуаций, в которых, внутри функций обратного вызова и замыканий, появляются области видимости, в которых используются ссылки на собственные методы и свойства с использованием ключевого слова this
, что является довольно распространённым источником путаницы и ошибок.
Рассмотрим следующий пример:
function testFunction() {
this.clearLocalStorage();
this.timer = setTimeout(function() {
this.clearBoard(); // что такое "this"?
}, 0);
};
Выполнение вышеприведённого кода приведёт к следующей ошибке: "Uncaught TypeError: undefined is not a function."
Причина появления этой ошибки заключается в том, что при вызове setTimeout()
мы, на самом деле, вызываем window.setTimeout()
. Как результат, анонимная функция, которая передаётся setTimeout()
, оказывается определена в контексте объекта window
, у которого нет метода clearBoard()
.
Традиционный подход к решению этой проблемы, совместимый со старыми версиями браузеров, заключается в том, чтобы просто сохранить ссылку на this
в некоей переменной, к которой потом можно будет обратиться из замыкания. Например, это может выглядеть так:
function testFunction () {
this.clearLocalStorage();
var self = this; // сохраним ссылку на 'this' пока оно является тем, чем мы его считаем!
this.timer = setTimeout(function(){
self.clearBoard();
}, 0);
};
В более современных браузерах можно использовать метод bind()
для передачи необходимой ссылки:
function testFunction () {
this.clearLocalStorage();
this.timer = setTimeout(this.reset.bind(this), 0); // осуществляем привязку к 'this'
};
function testFunction(){
this.clearBoard(); //возвращаемся к контексту правильного 'this'!
};
7. Uncaught RangeError: Maximum call stack
У возникновения этой ошибки, например, в Chrome, есть несколько причин. Одна из них — бесконечный вызов рекурсивной функции. Вот как выглядит эта ошибка в консоли разработчика Chrome:
Ошибка Maximum call stack size exceeded
Подобное может произойти и в том случае, когда функции передают значение, находящееся за пределами некоего допустимого диапазона значений. Многие функции принимают лишь числа, находящиеся в определённом диапазоне. Например, функции Number.toExponential(digits)
и Number.toFixed(digits)
принимают аргумент digits
, представленный числом от 0 до 20, а функция Number.toPrecision(digits)
принимает числа от 1 до 21. Взглянем на ситуации, в которых вызов этих и некоторых других функций приводит к ошибкам:
var a = new Array(4294967295); //OK
var b = new Array(-1); // ошибка!
var num = 2.555555;
document.writeln(num.toExponential(4)); //OK
document.writeln(num.toExponential(-2)); //ошибка!
num = 2.9999;
document.writeln(num.toFixed(2)); //OK
document.writeln(num.toFixed(25)); // ошибка!
num = 2.3456;
document.writeln(num.toPrecision(1)); //OK
document.writeln(num.toPrecision(22)); // ошибка!
8. TypeError: Cannot read property ‘length’
Эта ошибка возникает в Chrome при попытке прочесть свойство length
переменной, в которую записано undefined
. Взглянем на эту ошибку в консоли инструментов разработчика Chrome.
Ошибка Cannot read property ‘length’
Обычно, обращаясь к свойству length
, узнают длину массивов, но вышеописанная ошибка может возникнуть если массив не инициализирован, или если имя переменной скрыто в области видимости, недоступной из того места, где к этой переменной пытаются обратиться. Для того чтобы лучше понять сущность этой ошибки, рассмотрим следующий пример:
var testArray= ["Test"];
function testFunction(testArray) {
for (var i = 0; i < testArray.length; i++) {
console.log(testArray[i]);
}
}
testFunction();
При объявлении функции с параметрами эти параметры становятся для неё локальными переменными. В нашем примере это означает, что даже если в области видимости, окружающей функцию, есть переменная testArray
, параметр с таким же именем скроет эту переменную и будет восприниматься как локальная переменная функции.
Для того чтобы решить эту проблему, в нашем случае можно пойти одним из следующих двух путей:
- Удаление параметра, заданного при объявлении функции (как видно из примера, мы хотим работать с помощью функции с массивом, который объявлен за её пределами, поэтому тут можно обойтись и без параметра функции):
var testArray = ["Test"]; /* Предварительное условие: определение testArray за пределами функции */ function testFunction(/* без параметров */) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction();
- Вызов функции с передачей ей ранее объявленного массива:
var testArray = ["Test"]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(testArray);
9. Uncaught TypeError: Cannot set property
Когда мы пытаемся получить доступ к неопределённой переменной, то мы, фактически, работаем со значением типа undefined
, а этот тип не поддерживает чтение или запись свойств. В подобном случае приложение выдаст следующую ошибку:
"Uncaught TypeError cannot set property of undefined."
Взглянем на неё в браузере Chrome.
Ошибка Cannot set property
Если объект test
не существует, будет выдана ошибка "Uncaught TypeError cannot set property of undefined."
10. ReferenceError: event is not defined
Эта ошибка возникает при попытке получить доступ к неопределённой переменной, или к переменной, которая находится за пределами текущей области видимости. Взглянем на неё в консоли Chrome:
Ошибка ReferenceError: foo is not defined
Если вы сталкиваетесь с этой ошибкой при использовании системы обработки событий, убедитесь, что вы работаете с объектом события, переданным в качестве параметра. Более старые браузеры, вроде IE, предлагают глобальный доступ к событиям, но это не характерно для всех браузеров. Эту ситуацию пытаются исправить библиотеки вроде jQuery. В любом случае рекомендуется использовать именно тот объект события, которые передан в функцию обработки событий.
function myFunction(event) {
event = event.which || event.keyCode;
if(event.keyCode===13){
alert(event.keyCode);
}
}
Итоги
Надеемся, вы узнали из нашего рассказа об ошибках что-нибудь новое, такое, что поможет вам избежать ошибок в будущем, а может быть — уже помогло найти ответ на вопрос, который давно не давал вам покоя.
Уважаемые читатели! С какими JS-ошибками вы сталкивались в продакшне?
To give back to our community of developers, we looked at our database of thousands of projects and found the top 10 errors in JavaScript. We’re going to show you what causes them and how to prevent them from happening. If you avoid these «gotchas,» it’ll make you a better developer.
Because data is king, we collected, analyzed, and ranked the top 10 JavaScript errors. Rollbar collects all the errors for each project and summarizes how many times each one occurred. We do this by grouping errors according to their fingerprints. Basically, we group two errors if the second one is just a repeat of the first. This gives users a nice overview instead of an overwhelming big dump like you’d see in a log file.
We focused on the errors most likely to affect you and your users. To do this, we ranked errors by the number of projects experiencing them across different companies. If we looked only at the total number of times each error occurred, then high-volume customers could overwhelm the data set with errors that are not relevant to most readers.
Here are the top 10 JavaScript errors:
Each error has been shortened for easier readability. Let’s dive deeper into each one to determine what can cause it and how you can avoid creating it.
1. Uncaught TypeError: Cannot read property
If you’re a JavaScript developer, you’ve probably seen this error more than you care to admit. This one occurs in Chrome when you read a property or call a method on an undefined object. You can test this very easily in the Chrome Developer Console.
Uncaught TypeError: Cannot read property
can occur for many reasons, but a common one is improper initialization of state while rendering the UI components. Let’s look at an example of how this can occur in a real-world app. We’ll pick React, but the same principles of improper initialization also apply to Angular, Vue or any other framework.
class Quiz extends Component {
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
There are two important things realize here:
- A component’s state (e.g.
this.state
) begins life asundefined
. - When you fetch data asynchronously, the component will render at least once before the data is loaded – regardless of whether it’s fetched in the constructor,
componentWillMount
orcomponentDidMount
. When Quiz first renders,this.state.items
is undefined. This, in turn, meansItemList
gets items as undefined, and you get an error – «Uncaught TypeError: Cannot read property ‘map’ of undefined» in the console.
This is easy to fix. The simplest way: Initialize state with reasonable default values in the constructor.
class Quiz extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
The exact code in your app might be different, but we hope we’ve given you enough of a clue to either fix or avoid this problem in your app. If not, keep reading because we’ll cover more examples for related errors below.
2. TypeError: ‘undefined’ is not an object (evaluating
This is an error that occurs in Safari when you read a property or call a method on an undefined object. You can test this very easily in the Safari Developer Console. This is essentially the same as the above error for Chrome, but Safari uses a different error message.
3. TypeError: null is not an object (evaluating
This is an error that occurs in Safari when you read a property or call a method on a null object. You can test this very easily in the Safari Developer Console.
Interestingly, in JavaScript, null and undefined are not the same, which is why we see two different error messages. Undefined is usually a variable that has not been assigned, while null means the value is blank. To verify they are not equal, try using the strict equality operator:
One way this error might occur in a real world example is if you try using a DOM element in your JavaScript before the element is loaded. That’s because the DOM API returns null for object references that are blank.
Any JS code that executes and deals with DOM elements should execute after the DOM elements have been created. JS code is interpreted from top to down as laid out in the HTML. So, if there is a tag before the DOM elements, the JS code within script tag will execute as the browser parses the HTML page. You will get this error if the DOM elements have not been created before loading the script.
In this example, we can resolve the issue by adding an event listener that will notify us when the page is ready. Once the addEventListener
is fired, the init()
method can make use of the DOM elements.
<script>
function init() {
var myButton = document.getElementById("myButton");
var myTextfield = document.getElementById("myTextfield");
myButton.onclick = function() {
var userName = myTextfield.value;
}
}
document.addEventListener('readystatechange', function() {
if (document.readyState === "complete") {
init();
}
});
</script>
<form>
<input type="text" id="myTextfield" placeholder="Type your name" />
<input type="button" id="myButton" value="Go" />
</form>
4. (unknown): Script error
The (unknown): Script error occurs when an uncaught JavaScript error crosses domain boundaries in violation of the cross-origin policy. For example, if you host your JavaScript code on a CDN, any uncaught errors (errors that bubble up to the window.onerror handler, instead of being caught in try-catch) will get reported as simply «Script error» instead of containing useful information. This is a browser security measure intended to prevent passing data across domains that otherwise wouldn’t be allowed to communicate.
To get the real error messages, do the following:
1. Send the Access-Control-Allow-Origin header
Setting the Access-Control-Allow-Origin
header to signifies that the resource can be accessed properly from any domain. You can replace with your domain if necessary: for example, Access-Control-Allow-Origin: www.example.com
. However, handling multiple domains gets tricky, and may not be worth the effort if you’re using a CDN due to caching issues that may arise. See more here.
Here are some examples on how to set this header in various environments:
Apache
In the folders where your JavaScript files will be served from, create an .htaccess
file with the following contents:
Header add Access-Control-Allow-Origin "*"
Nginx
Add the add_header directive to the location block that serves your JavaScript files:
location ~ ^/assets/ {
add_header Access-Control-Allow-Origin *;
}
HAProxy
Add the following to your asset backend where JavaScript files are served from:
rspadd Access-Control-Allow-Origin: *
2. Set crossorigin=»anonymous» on the script tag
In your HTML source, for each of the scripts that you’ve set the Access-Control-Allow-Origin
header for, set crossorigin="anonymous"
on the SCRIPT tag. Make sure you verify that the header is being sent for the script file before adding the crossorigin
property on the script tag. In Firefox, if the crossorigin
attribute is present but the Access-Control-Allow-Origin
header is not, the script won’t be executed.
5. TypeError: Object doesn’t support property
This is an error that occurs in IE when you call an undefined method. You can test this in the IE Developer Console.
This is equivalent to the error «TypeError: ‘undefined’ is not a function» in Chrome. Yes, different browsers can have different error messages for the same logical error.
This is a common problem for IE in web applications that employ JavaScript namespacing. When this is the case, the problem 99.9% of the time is IE’s inability to bind methods within the current namespace to the this
keyword. For example, if you have the JS namespace Rollbar
with the method isAwesome.
Normally, if you are within the Rollbar
namespace you can invoke the isAwesome
method with the following syntax:
this.isAwesome();
Chrome, Firefox and Opera will happily accept this syntax. IE, on the other hand, will not. Thus, the safest bet when using JS namespacing is to always prefix with the actual namespace.
Rollbar.isAwesome();
6. TypeError: ‘undefined’ is not a function
This is an error that occurs in Chrome when you call an undefined function. You can test this in the Chrome Developer Console and Mozilla Firefox Developer Console.
As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of this/that confusion.
Consider this example code snippet:
function clearBoard(){
alert("Cleared");
}
document.addEventListener("click", function(){
this.clearBoard(); // what is “this” ?
});
If you execute the above code and then click on the page, it results in the following error «Uncaught TypeError: this.clearBoard is not a function». The reason is that the anonymous function being executed is in the context of the document, whereas clearBoard
is defined on the window.
A traditional, old-browser-compliant solution is to simply save your reference to this
in a variable that can then be inherited by the closure. For example:
var self=this; // save reference to 'this', while it's still this!
document.addEventListener("click", function(){
self.clearBoard();
});
Alternatively, in the newer browsers, you can use the bind()
method to pass the proper reference:
document.addEventListener("click",this.clearBoard.bind(this));
7. Uncaught RangeError
This is an error that occurs in Chrome under a couple of circumstances. One is when you call a recursive function that does not terminate. You can test this in the Chrome Developer Console.
It may also happen if you pass a value to a function that is out of range. Many functions accept only a specific range of numbers for their input values. For example, Number.toExponential(digits)
and Number.toFixed(digits)
accept digits from 0 to 100, and Number.toPrecision(digits)
accepts digits from 1 to 100.
var a = new Array(4294967295); //OK
var b = new Array(-1); //range error
var num = 2.555555;
document.writeln(num.toExponential(4)); //OK
document.writeln(num.toExponential(-2)); //range error!
num = 2.9999;
document.writeln(num.toFixed(2)); //OK
document.writeln(num.toFixed(105)); //range error!
num = 2.3456;
document.writeln(num.toPrecision(1)); //OK
document.writeln(num.toPrecision(0)); //range error!
8. TypeError: Cannot read property ‘length’
This is an error that occurs in Chrome because of reading length property for an undefined variable. You can test this in the Chrome Developer Console.
You normally find length defined on an array, but you might run into this error if the array is not initialized or if the variable name is hidden in another context. Let’s understand this error with the following example.
var testArray= ["Test"];
function testFunction(testArray) {
for (var i = 0; i < testArray.length; i++) {
console.log(testArray[i]);
}
}
testFunction();
When you declare a function with parameters, these parameters become local ones. This means that even if you have variables with names testArray
, parameters with the same names within a function will still be treated as local.
You have two ways to resolve your issue:
-
Remove parameters in the function declaration statement (it turns out you want to access those variables that are declared outside of the function, so you don’t need parameters for your function):
var testArray = ["Test"]; /* Precondition: defined testArray outside of a function */ function testFunction(/* No params */) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction();
-
Invoke the function passing it the array that we declared:
var testArray = ["Test"]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(testArray);
9. Uncaught TypeError: Cannot set property
When we try to access an undefined variable it always returns undefined
and we cannot get or set any property of undefined
. In that case, an application will throw “Uncaught TypeError cannot set property of undefined.”
For example, in the Chrome browser:
If the test
object does not exist, error will throw “Uncaught TypeError cannot set property of undefined.”
10. ReferenceError: event is not defined
This error is thrown when you try to access a variable that is undefined or is outside the current scope. You can test it very easily in Chrome browser.
If you’re getting this error when using the event handling system, make sure you use the event object passed in as a parameter. Older browsers like IE offer a global variable event, and Chrome automatically attaches the event variable to the handler. Firefox will not automatically add it. Libraries like jQuery attempt to normalize this behavior. Nevertheless, it’s best practice to use the one passed into your event handler function.
document.addEventListener("mousemove", function (event) {
console.log(event);
})
Conclusion
It turns out a lot of these are null or undefined errors. A good static type checking system like Typescript could help you avoid them if you use the strict compiler option. It can warn you if a type is expected but has not been defined. Even without Typescript, it helps to use guard clauses to check whether objects are undefined before using them.
We hope you learned something new and can avoid errors in the future, or that this guide helped you solve a head scratcher. Nevertheless, even with the best practices, unexpected errors do pop up in production. It’s important to have visibility into errors that affect your users, and to have good tools to solve them quickly.
Rollbar gives you visibility to production JavaScript errors and gives you more context to solve them quickly. For example, it offers additional debugging features like telemetry which tells you what happened on the user’s browser leading up to the error. That’s insight you don’t have outside of your local developer console. Learn more in Rollbar’s full list of features for JavaScript applications.
If you haven’t already, signup for a 14-day free trial of Rollbar and let us help you take control of impactful JavaScript errors. 🙂
I hit upon a problem in testing an Angular project this week that had me stumped for a while. The problem was this:
Every time I ran the test suite as a whole, they failed.
But if I ran each test file on its own… individually, they would pass.
I find more and more of my time lately is spent dealing with these sorts of things – they aren’t ‘development’ tasks, just annoyances that keep me from doing the thing I enjoy most – writing code.
Anyway, here’s the error:
INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket DGb_Xn6WLWQNnEEkUwtk with id 45807911 PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0) UrlManager should have get function FAILED TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$modules') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23514:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2454:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'undefined' is not an object (evaluating 'UrlManager.get') at /tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:42035:0 <- /my/project/src/components/UrlManager/spec/UrlManagerSpec.js:26:0 at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 PhantomJS 1.9.8 (Linux 0.0.0) UrlManager should return object for the others FAILED TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$injector') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'null' is not an object (evaluating 'currentSpec.$modules') at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23514:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2454:0) at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 TypeError: 'undefined' is not an object (evaluating 'UrlManager.get') at /tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:42053:0 <- /my/project/src/components/UrlManager/spec/UrlManagerSpec.js:44:0 at /my/project/node_modules/karma-jasmine/lib/boot.js:126 at /my/project/node_modules/karma-jasmine/lib/adapter.js:171 at http://localhost:9876/karma.js:182 at http://localhost:9876/context.html:257 PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 (2 FAILED) (0.415 secs / 0.026 secs) =============================== Coverage summary =============================== Statements : 17.48% ( 482/2758 ) Branches : 4.14% ( 40/967 ) Functions : 4.65% ( 30/645 ) Lines : 17.62% ( 477/2707 ) ================================================================================ [13:41:23] 'test' errored after 8.21 s [13:41:23] Error in plugin 'test' Message: Karma test returned 1 blimpyboy@project-dev1:~/Development/project$ ^C blimpyboy@project-dev1:~/Development/project$ ^C blimpyboy@project-dev1:~/Development/project$ gulp test [13:42:58] Warning: gulp version mismatch: [13:42:58] Global gulp is 3.9.0 [13:42:58] Local gulp is 3.8.11 [13:42:59] Using gulpfile ~/Development/project/gulpfile.js [13:42:59] Starting 'test'... INFO [framework.browserify]: Paths to browserify /my/project/src/components/PubSub/spec/**/*.js /my/project/src/components/UrlManager/spec/**/*.js INFO [framework.browserify]: Browserified in 6543ms, 6524kB INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/ INFO [launcher]: Starting browser PhantomJS INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket VrUi5MBGOl0J1oHWVKNw with id 50398227 PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config' PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 SUCCESS (0.056 secs / 0.035 secs) =============================== Coverage summary =============================== Statements : 20.01% ( 552/2758 ) Branches : 5.07% ( 49/967 ) Functions : 6.98% ( 45/645 ) Lines : 20.21% ( 547/2707 ) ================================================================================ [13:43:07] Finished 'test' after 8.1 s blimpyboy@project-dev1:~/Development/project$
I’m aware the coverage isn’t so good – but actually this is not the true coverage as I’d stripped out a whole bunch of tests by bastardising the karma.conf.js file to try and isolate the problem. No… seriously, I promise 🙂
Anyway, it turned out that the solution to this was actually pretty simple.
Of course, nearly all solutions to programming problem seem simple once you have figured out the problem. Hindsight is such a wonderful thing.
But in this case, the problem was that a bunch of variables had been declared inside on the of describe blocks:
describe("SomeModule module", function () { beforeEach(angular.mock.module('Some.Module')); var angular = require('angular'); var scope; require('../../../scripts/app.js'); require('angular-mocks'); var SomeModule;
And the solution was to simply move all the setup stuff outside of the describe block:
var angular = require('angular'); var scope; require('../../../scripts/app.js'); require('angular-mocks'); var SomeModule; describe("SomeModule module", function () { beforeEach(angular.mock.module('Some.Module'));
An easy fix.
The real annoyance here was that I went through this whole project alphabetically, and this particular module began with the letter ‘P’, so I’d been through over half the code before I spotted it. Hours I will never get back.
Still, it’s fixed now, and hopefully now you can save a few hours if you ever suffer from this problem yourself.
От автора: чтобы вернуть сообщество разработчиков, мы рассмотрели нашу базу данных по тысячам проектов и нашли 10 самых распространённых ошибок в JavaScript. Мы собираемся показать вам, что к ним приводит и как это предотвратить. Если ни одна ошибка JavaScript не встречается в вашем коде, это делает вас лучшим разработчиком.
Поскольку всем управляют данные, мы собрали, проанализировали и оценили первые 10 ошибок JavaScript. Rollbar собирает все ошибки из каждого проекта и суммирует, сколько раз каждая из них возникала. Мы делаем это, группируя ошибки в соответствии с их отпечатками пальцев . В принципе, группируется по две ошибки, если вторая — это просто повторение первой. Это дает пользователям хороший обзор вместо огромной свалки, какую вы видели в файле журнала.
Мы сосредоточились на ошибках, которые скорее всего повлияют на вас и ваших пользователей. Чтобы сделать это, мы оценили ошибки по количеству проектов, испытывающихся в разных компаниях. Если бы мы посмотрели только на общее количество раз, когда произошла каждая ошибка, то клиенты большого объема могли бы подавить набор данных с ошибками, которые не имеют отношения к большинству читателей.
Вот первые 10 ошибок JavaScript:
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Узнать подробнее
Ошибки были сокращены для удобства чтения. Давайте погрузимся глубже в каждую, чтобы определить, что может вызвать её, и как избежать их появления.
1. Uncaught TypeError: Cannot read property
Если вы разработчик JavaScript, то, вероятно, видели эту ошибку очень много раз. Это происходит в Chrome, когда вы читаете свойство или вызываете метод на неопределенный объект. Это можно очень легко проверить в консоли разработчика Chrome.
Это может произойти по многим причинам, но чаще всего это неправильная инициализация состояния при рендеринге компонентов пользовательского интерфейса. Давайте рассмотрим пример того, как это может произойти в реальном приложении. Мы выберем React, но те же принципы неправильной инициализации применимы и к Angular, Vue или любой другой структуре.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Quiz extends Component { componentWillMount() { axios.get(‘/thedata’).then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } } |
Здесь понимаются две важные вещи:
Состояние компонента (например, this.state ) начинает жизнь как undefined.
Когда вы извлекаете данные асинхронно, компонент будет отображаться как минимум один раз перед загрузкой данных — независимо от того, выбрана ли она в конструкторе componentWillMount или componentDidMount . Когда Quiz отображается впервые, this.state.items не определен. Это, в свою очередь, означает, что ItemList получает элементы как неопределенные, и вы получаете сообщение об ошибке «Uncaught TypeError: Невозможно прочитать карту свойств» в консоли.
Это легко исправить. Самый простой способ: инициализировать состояние с разумными значениями по умолчанию в конструкторе.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Quiz extends Component { // Added this: constructor(props) { super(props); // Assign state itself, and a default value for items this.state = { items: [] }; } componentWillMount() { axios.get(‘/thedata’).then(res => { this.setState({items: res.data}); }); } render() { return ( <ul> {this.state.items.map(item => <li key={item.id}>{item.name}</li> )} </ul> ); } } |
Код в вашем приложении может отличаться, но мы надеемся, что дали вам достаточно информации, чтобы исправить или избежать этой проблемы. Если нет, продолжайте читать, потому что далее мы рассмотрим больше примеров связанных с ошибками.
2. TypeError: ‘undefined’ is not an object (evaluating
Эта ошибка возникает в Safari при чтении свойства или вызове метода для неопределенного объекта. Вы можете проверить это в консоли разработчика Safari. Это по сути то же самое, что и вышеприведенная ошибка для Chrome, только Safari использует другое сообщение об ошибке.
3. TypeError: null is not an object (evaluating
Это ошибка, которая возникает в Safari при чтении свойства или вызове метода для пустого объекта. Проверить это можно в консоли разработчика Safari.
Интересно, что в JavaScript значения null и undefined не совпадают, поэтому мы видим два разных сообщения об ошибках. Undefined обычно является переменной, которая не была назначена, а null означает, что значение пустое. Чтобы убедиться, что они не одно и то же, попробуйте использовать строгий оператор равенства:
Один из способов, которым эта ошибка может возникнуть в реальном мире — это попытка использовать элемент DOM в JavaScript перед загрузкой элемента. Это потому, что DOM API возвращает null для ссылок на пустые объекты.
Любой JS-код, который выполняет и обрабатывает элементы DOM, должен выполняться после создания элементов DOM. JS-код интерпретируется сверху вниз, как изложено в HTML. Итак, если перед элементами DOM есть тег, код JS в теге скрипта будет выполняться, когда браузер анализирует HTML-страницу. Вы получите эту ошибку, если элементы DOM не были созданы до загрузки сценария.
В этом примере мы можем решить проблему, добавив прослушиватель событий, который уведомит нас, когда страница будет готова. После addEventListener метод init() может использовать элементы DOM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<script> function init() { var myButton = document.getElementById(«myButton»); var myTextfield = document.getElementById(«myTextfield»); myButton.onclick = function() { var userName = myTextfield.value; } } document.addEventListener(‘readystatechange’, function() { if (document.readyState === «complete») { init(); } }); </script> <form> <input type=«text» id=«myTextfield» placeholder=«Type your name» /> <input type=«button» id=«myButton» value=«Go» /> </form> |
4. (unknown): Script error
Ошибка скрипта возникает, когда ошибка неперехваченного JavaScript пересекает границы домена и нарушает политику перекрестного происхождения. Например, если вы размещаете свой код JavaScript на CDN, любые неперехваченные ошибки (ошибки, которые появляются в обработчике window.onerror, вместо того, чтобы быть пойманным в try-catch) будут переданы как просто «Script error» вместо того, чтобы содержать полезную информацию. Эта мера безопасности браузера предназначена для предотвращения передачи данных по доменам, которые в противном случае не были бы допущены к коммуникации.
Чтобы получить реальные сообщения об ошибках, выполните следующие действия:
1. Отправьте заголовок Access-Control-Allow-Origin
Установка заголовка Access-Control-Allow-Origin в * означает, что к ресурсу можно получить доступ из любого домена. Вы можете заменить * своим доменом, если необходимо: например, Access-Control-Allow-Origin: www.example.com . Если вы используете CDN из-за проблем с кэшированием, которые могут возникнуть, обработка нескольких доменов становится сложной и нельзя не приложить усилий. Подробнее см. здесь.
Вот несколько примеров того, как установить этот заголовок в различных средах:
Apache
В папках, где будут храниться ваши файлы JavaScript, создайте файл .htaccess со следующим содержимым:
Header add Access—Control—Allow—Origin «*» |
Nginx
Добавьте директиву add_header в блок местоположения, который служит файлам JavaScript:
location ~ ^/assets/ { add_header Access—Control—Allow—Origin *; } |
HAProxy
Добавьте в ресурс, где будут загружены файлы JavaScript:
rspadd Access—Control—Allow—Origin: * |
2. Установите crossorigin = «anonymous» в теге скрипта
В HTML-источнике для каждого из сценариев, где вы установите заголовок Access-Control-Allow-Origin, в теге SCRIPT установите crossorigin=»anonymous». Убедитесь, что заголовок отправляется для файла сценария, перед добавлением свойства crossorigin в тег скрипта. В Firefox, если атрибут crossorigin присутствует, но заголовок Access-Control-Allow-Origin отсутствует, сценарий не будет выполнен.
5. TypeError: Object doesn’t support property
Это ошибка, которая возникает в IE при вызове неопределенного метода. Вы можете проверить это в IE Developer Console.
Это эквивалентно ошибке «TypeError: ‘undefined’ is not a function» в Chrome. Да, разные браузеры могут иметь разные сообщения для одной и той же ошибки.
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Узнать подробнее
Это обычная проблема для IE в веб-приложениях, использующих пространство имен JavaScript. Когда это так, проблема в 99,9% случаев— это неспособность IE связать методы в текущем пространстве имен с ключевым словом this. Например, если у вас есть пространство имен имен Rollbar с помощью метода isAwesome. Обычно, если вы находитесь в пространстве имен Rollbar вы можете вызвать метод isAwesome со следующим синтаксисом:
Chrome, Firefox и Opera с радостью согласятся с этим синтаксисом. С другой стороны, IE не станет. Таким образом, самая безопасная ставка при использовании JS namespacing — это префикс с фактическим пространством имен.
6. TypeError: ‘undefined’ is not a function
Это ошибка, возникающая в Chrome при вызове неопределенной функции. Вы можете протестировать это в консоли разработчика Chrome и в Mozilla Firefox.
Поскольку на протяжении многих лет методы кодирования JavaScript и шаблоны проектирования становятся все более изощренными, наблюдается соответствующее увеличение распространения областей самореференции в обратных вызовах и закрытиях, которые являются довольно распространенным источником этой путаницы.
Рассмотрим фрагмент кода:
function clearBoard(){ alert(«Cleared»); } document.addEventListener(«click», function(){ this.clearBoard(); // what is “this” ? }); |
Выполнение вышеуказанного кода приводит к следующей ошибке: «Uncaught TypeError: undefined is not function». Причина, по которой вы получаете эту ошибку, заключается в том, что при вызове setTimeout() вы вызываете window.setTimeout(). В результате анонимная функция, передаваемая setTimeout(), определяется в контексте объекта окна, у которого нет clearBoard().
Традиционное решение, совместимое со старым браузером — просто сохранить ссылку на this в переменной, которая затем может быть унаследована закрытием. Например:
var self=this; // save reference to ‘this’, while it’s still this! document.addEventListener(«click», function(){ self.clearBoard(); }); |
Кроме того, в новых браузерах для передачи правильной ссылки вы можете использовать метод bind():
document.addEventListener(«click»,this.clearBoard.bind(this)); |
7. Uncaught RangeError: Maximum call stack
Это ошибка, которая возникает в Chrome при нескольких обстоятельствах. Одно из них — когда вы вызываете рекурсивную функцию, которая не завершается. Вы можете протестировать это в консоли разработчика Chrome.
Это также может произойти, если вы передадите значение функции, находящейся за пределами допустимого диапазона. Многие функции принимают только определенный диапазон чисел для своих входных значений. Например, Number.toExponential(digits) и N umber.toFixed(digits) принимают цифры от 0 до 20, а Number.toPrecision(digits) принимают цифры от 1 до 21.
var a = new Array(4294967295); //OK var b = new Array(—1); //range error var num = 2.555555; document.writeln(num.toExponential(4)); //OK document.writeln(num.toExponential(—2)); //range error! num = 2.9999; document.writeln(num.toFixed(2)); //OK document.writeln(num.toFixed(25)); //range error! num = 2.3456; document.writeln(num.toPrecision(1)); //OK document.writeln(num.toPrecision(22)); //range error! |
8. TypeError: Cannot read property ‘length’
Это ошибка, которая возникает в Chrome из-за свойства длины чтения для неопределенной переменной. Вы можете протестировать это в консоли разработчика Chrome.
Обычно вы определяете длину, определенную в массиве, но вы можете столкнуться с этой ошибкой, если массив не инициализирован или если имя переменной скрыто в другом контексте. Давайте рассмотрим эту ошибку на следующем примере.
var testArray= [«Test»]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(); |
Когда вы объявляете функцию с параметрами, эти параметры становятся локальными. Это означает, что даже если у вас есть переменные с именами testArray , параметры с одинаковыми именами внутри функции будут по-прежнему рассматриваться как локальные.
У вас есть два способа решить эту проблему:
1. Удалите параметры в объявлении функции (оказывается, вы хотите получить доступ к тем переменным, которые объявлены вне функции, поэтому вам не нужны параметры для вашей функции):
var testArray = [«Test»]; /* Precondition: defined testArray outside of a function */ function testFunction(/* No params */) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(); |
2. Вызовите функцию, передав ей массив, который мы объявили:
var testArray = [«Test»]; function testFunction(testArray) { for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(testArray); |
9. Uncaught TypeError: Cannot set property
Когда мы пытаемся получить доступ к неопределенной переменной, она всегда возвращает undefined, а мы не можем получить или установить любое свойство undefined. В этом случае приложение будет выбрасывать “Uncaught TypeError cannot set property of undefined.”
Например, в браузере Chrome:
Если объект test не существует, будет выдаваться ошибка: “Uncaught TypeError cannot set property of undefined.”
10. ReferenceError: event is not defined
Эта ошибка возникает при попытке получить доступ к переменной, которая не определена или находится за пределами текущей области. Вы можете легко протестировать её в браузере Chrome.
Если вы получаете эту ошибку при использовании системы обработки событий, убедитесь, что вы используете объект события, переданный в качестве параметра. Старые браузеры, такие как IE, предлагают событие глобальной переменной, но не поддерживаются во всех браузерах. Библиотеки, подобные jQuery, пытаются нормализовать это поведение. Тем не менее, лучше использовать тот объект, который передается в функцию обработчика событий.
document.addEventListener(«mousemove», function (event) { console.log(event); }) |
Вывод
Мы надеемся, что вы узнали что-то новое и сможете избежать ошибок в будущем или, что это руководство помогло вам решить возникшую проблему. Тем не менее, даже при использовании лучших практик в производстве появляются неожиданные ошибки. Важно иметь видимость ошибок, которые влияют на пользователей, и хорошие инструменты для их быстрого решения.
Rollbar предлагает уникальные возможности для приложений JavaScript, таких как телеметрия, которые сообщают вам, что произошло в браузере пользователя, что приводит к ошибке. Это прозрение, которого у вас нет за пределами локальной консоли разработчика.
Автор: Jason Skowronski
Источник: //rollbar.com/
Редакция: Команда webformyself.
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Узнать подробнее
JavaScript. Быстрый старт
Изучите основы JavaScript на практическом примере по созданию веб-приложения
Смотреть
I am trying to write a script that changes the color of an object to a different color (In this instance I am changing all blue solids to red solids). The script works just fine until I include an object in the timeline of a comp that is not defined in the library. For example if I use the rectangle tool to draw a square it creates an object in the timeline that does not appear in the library. Does anyone know how I could tell AE to ignore these objects when it comes across them instead of giving me the «Null is not an object» error and stopping the script from finishing? I’m very new to scripting so any advice is welcomed.
Here is the script I am using:
try{
//———————————-Variables———————————-
var proj = app.project;
var itemTotal = proj.numItems;
var solidColor = [1, 0, 0];
var curItem, curComp, totalComps, totalLayers, curLayer, curLayerIndex, curLayerSource;
var itemAry = new Array();
//———————————-Loop through project items———————————-
app.beginUndoGroup(«Blue to Red»);
for(var i = 1; i <= itemTotal; i++){
//item assignment
curItem = proj.item(i);
//Check if item is comp
if(curItem instanceof CompItem){
itemAry[itemAry.length] = curItem;
}
}
totalComps = itemAry.length;
for(var c = 0; c < totalComps; c++){
//—————————————————————
//———————————-Variable assignment———————————-
curComp = itemAry;
totalLayers = curComp.numLayers;
//Loop through layers
for(var l=1; l<=totalLayers; l++){
curLayer = curComp.layer(l);
curLayerIndex = curLayer.index;
curLayerSource = curLayer.source.mainSource;
//——Check layer, if it is a solid and it’s blue, change it to red (Change this to set new color)———
if(curLayerSource instanceof SolidSource && curLayerSource.color == «0,0,1»){
curLayerSource.color = [1,0,0];
}
//Update info panel with progress
writeLn(«Layer » + curLayerIndex.toString() + » updated»);
}
//——————————————————————
}
app.endUndoGroup();
alert(«All Done.»);
//If an error occurs, catch it and show me
}catch(err){
alert(«Error at line # » + err.line.toString() + «r» + err.toString());
}