10 распространённых ошибок начинающий JavaScript-программистов

в 8:09, , рубрики: Без рубрики

JavaScript считается простым языком программирования. Но впечатления обманчивы. Есть ряд моментов, на которые стоит обратить пристальное внимание. Мы перевели статью для тех, кто только собирается постигать азы JavaScript. Итак, 10 самых самых распространённых ошибок.

1. Отсутствуют фигурные скобки

Пожалуй, главная ошибка всех новичков – отсутствие фигурных скобок после if, else, while и for. Согласно правилам, их действительно можно и не ставить. Но игнорирование скобок часто становится причиной багов.

// Say hello to Gandalf
hello('Gandalf');

function hello(name){

	// This code doesn't do what the indentation implies!

	if(name === undefined)
		console.log('Please enter a username!');
		fail();

	// The following line is never reached:

	success(name);
}

function success(name){
	console.log('Hello, ' + name + '!');
}

function fail(){
	throw new Error("Name is missing. Can't say hello!");
}

Отступ у вызова fail() может создать иллюзию, что он относится к if. Но он будет вызываться всегда.

2. Отсутствует точка с запятой

Во время парсинга в JavaScript происходит процесс автоматической вставки точек с запятой. Интерпретатор с радостью добавит за вас недостающие точки с запятой (не всегда там, где нужно). Вообще-то, эта функция задумывалась в помощь новичкам, но часто, напротив, вредит им. Рассмотрим на примере:

// This code results in a type error. Adding semicolons will fix it.

console.log('Welcome the fellowship!')

['Frodo', 'Gandalf', 'Legolas', 'Gimli'].forEach(function(name){
	hello(name)
})

function hello(name){
	console.log('Hello, ' + name + '!')
}

Из-за отсутствия точки с запятой в строке 3 интерпретатор думает, что открывающая скобка в пятой строке – это попытка прописать доступ к свойству, а не отдельный массив данных (чего не подразумевает логика программы).
Чтобы не допустить путаницы, проще всегда расставлять знаки самостоятельно. Хотя некоторые разработчики с этим не согласны.

3. Сложности с приведением типов

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

// Listen for the input event on the textbox

var textBox = document.querySelector('input');

textBox.addEventListener('input', function(){

	// textBox.value holds a string. Adding 10 appends 
	// the string '10', it doesn't perform an addition..

	console.log(textBox.value + ' + 10 = ' + (textBox.value + 10));

});

Проблема может быть легко исправлена с помощью ParseInt (textbox.value, 10), превращающего строку в число, прежде чем добавлять к ней 10.
Чтобы избежать неясностей с преобразованием переменных, можно использовать проверку строгого равенства (===), которая позволяет удостовериться в том, что типы обрабатываемых переменных совпадают.

4. Все забывают о var

Var – оператор, объявляющий переменную. Новички очень часто забывают писать его. Javascript великодушно прощает такую невнимательность и объявляет переменные без var как глобальные. Однако в ряде случаев забывчивость может привести к фатальному результату. Вот пример, в котором, помимо var, отсутствует запятая при объявлении нескольких переменных сразу.

var a = 1, b = 2, c = 3;

function alphabet(str){
	var a = 'A', b = 'B'	// Oops, missing ',' here!
		c = 'C', d = 'D';

	return str + ' ' + a + b + c + '…';
}

console.log( alphabet("Let's say the alphabet!") );

// Oh no! Something went wrong! c has a new value!
console.log(a, b, c);

Достигнув 4 строки, интерпретатор поставит точку с запятой автоматически, а затем интерпретирует c и d в строке 5 как объявление глобальных переменных. Это приведёт к тому, что значение c станет равным 'C', а не 3. Здесь можно почитать подробнее о подводных камнях JavaScript.

5. Арифметические операции с числами с плавающей точкой

Эта ошибка встречается не только в JavaScript, а практически во всех языках программирования. Из-за особенностей записи чисел с плавающей точкой в памяти, арифметические операции между ними могут быть не абсолютно точными. Пример:

var a = 0.1, b = 0.2;

// Surprise! this is false:
console.log(a + b == 0.3);

// Because 0.1 + 0.2 does not produce the number that you expect:
console.log('0.1 + 0.2 = ', a + b);

Чтобы обойти подобные ошибки стороной, используйте при расчётах лишь целые числа, а не десятичные дроби. Если же вы работаете, скажем, с денежными расчётами, где неизбежно указание десятых и сотых долей целого, используйте такие библиотеки, как bignumber.js.

6. Излишнее использование конструкторов

Когда Java или C# программисты начинают писать на JavaScript, часто используют для создания объектов конструкторы new Array(), new Object(), new String(). Это работает, но иногда может приводить к ошибкам. Пример:

/* Using array constructors is valid, but not recommended. Here is why. */

// Create an array with four elements:

var elem4 = new Array(1,2,3,4);

console.log('Four element array: ' + elem4.length);

// Create an array with one element. It doesn't do what you think it does:

var elem1 = new Array(23);

console.log('One element array? ' + elem1.length);

/* String objects also have their warts */

var str1 = new String('JavaScript'),
	str2 = "JavaScript";

// Strict equality breaks:

console.log("Is str1 the same as str2?", str1 === str2);

Рекомендуем использовать вместо конструкторов прямое задание массива с помощью [], {}, "". Кстати, размер массива задавать заранее не нужно.

7. Непонимание принципов работы области видимости

Область видимости — это участок кода (например, функция), в пределах которого имя переменной продолжает быть связанным с этой переменной и возвращать её значение.
Рассмотрим такой случай:

// Print the numbers from 1 to 10, 100ms apart. Or not.

for(var i = 0; i < 10; i++){
	setTimeout(function(){
		console.log(i+1);
	}, 100*i);
}

/* To fix the bug, wrap the code in a self-executing function expression:

for(var i = 0; i < 10; i++){

	(function(i){
		setTimeout(function(){
			console.log(i+1);
		}, 100*i);
	})(i);

}				

*/

В данной ситуации выполнение функции откладывается с помощью setTimeout. К тому моменту, как она начинает работу, цикл уже закончится и переменная i будет равна 11.
Закомментированное решение будет работать, так как она копирует i и для каждой функции timeout().
Материал по теме.

8. Использование Eval

Eval is evil. Не стоит к нему обращаться, если вы не можете чётко объяснить себе, зачем это нужно. Как правило, достичь цели другим способом получается гораздо быстрее и проще.

/* Using eval to access properties dynamically */

var obj = {
	name: 'Foo Barski',
	age: 30,
	profession: 'Programmer'
};

// Which property to access?
var access = 'profession';

// This is a bad practice. Please don't do it:
console.log( eval('obj.name + " is a " + obj.' + access) );

// Instead, use array notation to access properties dynamically:
console.log( obj.name + " is a " + obj[access]);

/* Using eval in setTimout */

// Also bad practice. It is slow and difficult to read and debug:
setTimeout(' if(obj.age == 30) console.log("This is eval-ed code, " + obj[access] + "!");', 100);

// This is better:
setTimeout(function(){

	if(obj.age == 30){
		console.log('This code is not eval-ed, ' + obj[access] + '!');
	}

}, 100);

Код внутри eval представлен строкой, что затрудняет вывод и понимание отладочной информации. Также вам придётся внимательно следить за экранированием кавычек. Наконец, eval попросту работает медленнее, чем аналогичная конструкция на JavaScript.

9. Непонимание принципов асинхронного кода

Уникальным для JavaScript является тот факт, что его код выполняется практически асинхронно, то есть, для того чтобы проследить его выполнение, вам необходимо внимательно изучить стек вызовов. Новичков это обычно ставит в тупик. Вот пример с использованием сервиса для определения вашего местоположения по IP:

var userData = {};

// Fetch the location data for the current user.
load();

// Output the location of the user. Oops, it doesn't work! Why?
console.log('Hello! Your IP address is ' + userData.ip + ' and your country is ' + userData.country_name);

// The load function will detect the current visitor's ip and location with ajax, using the
// freegeoip service. It will place the returned data in the userData variable when it's ready.

function load(){

	$.getJSON('http://freegeoip.net/json/?callback=?', function(response){
		userData = response;

		// Uncomment this line to see what is returned:
		// console.log(response);
	});
}

Несмотря на то, что вызов console.log расположен в коде после load(), на самом деле его запуск происходит перед извлечением данных.

10. Злоупотребление обработчиками событий

Предположим, вы хотите обрабатывать клик по кнопке, но только при установленном в чекбоксе флажке. Вот как это мог бы сделать начинающий, используя JQuery:

var checkbox = $('input[type=checkbox]'),
	button = $('button');

// We want to listen for clicks only when the checkbox is marked.

checkbox.on('change', function(){

	// Is the checkbox checked?

	if(this.checked){

		// Listen for clicks on the button. 

		button.on('click', function(){

			// This alert is called more than once. Why?

			alert('Hello!');
		});
	}
});

Так делать не стоит. В идеале, каждое событие должно обрабатываться одним обработчиком событий, как, например, это сделано для проверки изменения чекбокса. Но для кнопки будут создаваться дубли обработчиков, которые никогда не будут выгружены из памяти.

Совет

Один из лучших способов избежать ошибок – использовать JSHint. Некоторые IDE предлагают встроенную интеграцию с этим инструментом, таким образом, код автоматически проверяется в процессе написания.
Надеемся, в нашем топ-10 вы нашли для себя что-то интересное. Всегда рады вашим дополнениям и комментариям.

Автор: htdt

Источник

Поделиться

* - обязательные к заполнению поля