От создателя: JavaScript — это язык программирования, который дозволяет реализовывать на интернет-страницах сложные функции, и, если кратко, вы уже много понимаете о JS, потому что это самый пользующийся популярностью язык программирования в 2019 году (это не наше мировоззрение, все числа мы получили из Developer Survey 2019 от Stackoverflow). Если вы не слышали о этом опросе, вы должны ознакомиться с ним, до этого чем мы продолжим.
Так как JavaScript является основой хоть какого веб-приложения, мы не будем дискуссировать достоинства JS либо перечень его способностей. Заместо этого мы разглядим обычные ошибки, которые практически любой программер JS совершал за свою карьеру.
Согласно тому же опросу Stackoverflow, 41% программистов, принявших роль, имеют проф опыт написания кода наименее 5 лет.
Эта статья в главном создана для таковых разрабов. Новейшие создатели (0–2 года) могут отыскать в статье полезные примеры, поэтому что это нехороший код, из которого вы сможете извлечь уроки. Наиболее бывалые создатели (от 3 лет) могут улыбнуться, узнав ошибки, которые они совершали в прошедшем. В любом случае, потратив некое время на чтение данной статьи, вы получите или познания, или наслаждение. Услаждайся чтением!
Перечень ошибок:
Вы помните разницу меж «=», «==» и «===»?
Запамятовали о области деяния переменных?
Недопонимание различия меж «let», «const» и «var».
Неправильные ссылки на способы экземпляра.
Трудности использования this.
Вы помните разницу меж «=», «==» и «===»?
Быстрее всего, вы сталкивались с схожей неувязкой:
JavaScript
var x = 1;
if (x = 7) {
alert(«Hello»);
} else {
alert(«Nope»);
}
123456 | var x = 1;if (x = 7) { alert(«Hello»); } else { alert(«Nope»);} |
И вы получали «Hello»! Почему? Ответ весьма прост: вы не осознаете разницу меж 3 операторами, упомянутыми выше. Это не непростая ошибка, и как вы поймете ее, вы навряд ли забудете о этом. Так как эта ошибка весьма ординарна, вы сможете пропустить ее, когда дело доходит до критерий выхода из цикла.
Давайте покончим с сиим и пойдем далее. «=» — это оператор равенства, потому он употребляется для присваивания. В нашем примере мы присваиваем «x» значение семь в условии и получаем слова приветствия «Hello».
Верный код смотрится так:
JavaScript
var x = 1;
if (x == 7) {
alert(«Hello»);
} else {
alert(«Nope»);
}
123456 | var x = 1;if (x == 7) { alert(«Hello»);} else { alert(«Nope»);} |
Мы получаем «Nope».
«==» — оператор сопоставления. Почему? Поэтому что он дозволяет преобразовывать значения из 1-го типа в иной, чтоб сопоставить их. Даже если мы присваиваем x строковое значение «7» и сравниваем его с числовым значением «7», код возвращает нам «Hello». Но приведенный ниже код возвращает «Nope»:
Почему? Поэтому что «===» является оператором сопоставления серьезного равенства. Если этот оператор возвращает «true», это значит, что наши значения схожи как по значению, так и по типу. Для «===» есть аналог — способ Object.is. Он имеет некие различия в обработке значений -0, +0 и NaN, но некие из вас знают, каковы эти различия, в то время как остальные могут обратиться к управлению по JavaScript. И совершенно, рекомендуется:
Если у вас есть какие-либо сомнения относительно способов либо функций JS, вы постоянно сможете отыскать их в Гугл, но мы настоятельно советуем применять Управление по JavaScript.
Запамятовали о области видимости переменных?
Еще одна достаточно обычная ошибка:
JavaScript
let arr = [1,2,3,4,5,6,7];
var j;
for (j=0; j < arr.length; j++) {
console.log (arr[j]);
}
// …some long code
console.log ( j ); // we get the number “7”
1234567 | let arr = [1,2,3,4,5,6,7];var j;for (j=0; j < arr.length; j++) { console.log (arr[j]);} // …some long codeconsole.log ( j ); // we get the number “7” |
Шпаргалка по импорту и экспорту ES6
И просто запамятовать, что наша переменная меняет свое значение опосля цикла. Эта ошибка имеет пространство не только лишь в JS, да и в целом. В неких языках вы определяете переменную лишь снутри цикла, и она уничтожается опосля окончания цикла, но не в JavaScript.
И обратная ситуация, когда вы пытаетесь получить доступ к переменной, которая была определена в локальной области (это относится к области деяния функции). Пример:
JavaScript
function myFunction() {
var me = «You can’t touch me!»;
}
console.log(me);
1234 | function myFunction() { var me = «You can’t touch me!»;} console.log(me); |
«me» не определено, извините, вы сможете связаться со своим адвокатом либо просто уяснить область внедрения переменных в JavaScript. Верный код:
JavaScript
var me;
function myFunction() {
me = «You can’t touch me!»;
}
console.log(me + ‘I Can, sorry’);
12345 | var me;function myFunction() { me = «You can’t touch me!»;}console.log(me + ‘I Can, sorry’); |
Очередной пример, связанный с главным словом let, введенным в JS в 2015 году для объявления переменных (ECMA Script 6):
JavaScript
let arr = [1,2,3,4,5,6,7];
for (let j = 0; j < arr.length; j++) {
console.log(arr[j]); // the output: 1, 2, 3, 4, 5, 6, 7
}
console.log(j) // j = 0.
12345 | let arr = [1,2,3,4,5,6,7];for (let j = 0; j < arr.length; j++) { console.log(arr[j]); // the output: 1, 2, 3, 4, 5, 6, 7} console.log(j) // j = 0. |
Ключевое слово let не изменило переменную «j» по сопоставлению с первым примером. И этот вопросец — тема нашего последующего раздела.
Недопонимание различия меж «let», «const» и «var»
Это тесновато соединено с предшествующей неувязкой, но, так как практически любой из нас гуглил «разница меж var, const и let», мы выделяем раздельно этот вопросец. Давайте поначалу поглядим на код ниже:
JavaScript
console.log(x); // undefined
var x = 5;
console.log(x); // the output is 5
123 | console.log(x); // undefinedvar x = 5;console.log(x); // the output is 5 |
Код логичен как, и вывод, вопросцев нет. Иной пример:
JavaScript
console.log(x); // Error: cannot access “x” before the initialization
let x = 5;
console.log(x);
123 | console.log(x); // Error: cannot access “x” before the initializationlet x = 5;console.log(x); |
Причина в том, что var — это область деяния функции, а let — это область деяния блока. Когда вы объявляете переменную при помощи главного слова let, вы перемещаетесь в начало блока. Это может привести к ошибке ссылки при попытке доступа к переменной до инициализации.
Она именуется «временная мертвая зона», если вы желаете выяснить больше о ней, вы сможете посетить официальный сайт для разрабов JS Mozilla JavaScript Guide.
Но мы перебегаем к нашему последующему участнику и показываем пример, чтоб обрисовать все:
JavaScript
let a = 5;
var b = 10;
const c = 11;
if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is global
const c = 15; // The scope is inside the if-block
console.log(a); // 4,
console.log(b); // 1
console.log(c); // 15
}
console.log(a); // 5, the value changes to the initial
console.log(b); // 1, the value from if-block saves
console.log(c); // 11, the value changes to the initial
12345678910111213141516 | let a = 5;var b = 10;const c = 11; if (a === 5) { let a = 4; // The scope is inside the if-block var b = 1; // The scope is global const c = 15; // The scope is inside the if-block console.log(a); // 4, console.log(b); // 1 console.log(c); // 15} console.log(a); // 5, the value changes to the initial console.log(b); // 1, the value from if-block savesconsole.log(c); // 11, the value changes to the initial |
И крайний код этого раздела:
JavaScript
a = 10; // it’s OK, the value of a is changed to 10
b = 20; // it’s OK, the value of b is changed to 20
c = 7; // SyntaxError: Identifier «c» has already beed declared
const c = 15; // The same error
1234 | a = 10; // it’s OK, the value of a is changed to 10b = 20; // it’s OK, the value of b is changed to 20c = 7; // SyntaxError: Identifier «c» has already beed declared const c = 15; // The same error |
Что вышло? В блоке if мы объявили переменные «a» и «c» и изменили значение глобальной переменной «b». Вне блока «a» и «c» возвратились к своим исходным значениям. Опосля этого мы попробовали поменять значения всех переменных: let и var разрешают нам это созодать, а const возвращает ошибку. Причина в том, что const заявляет доступную лишь для чтения ссылку на значение в определенной области (оно быть может локальным либо глобальным). Вот почему нам удалось объявить новое значение переменной «c» в блоке if, но нам не удалось поменять значение вне его.
Неправильные ссылки на способы экземпляра
Давайте сделаем новейший объект и используем свойство prototype функции для прибавления способа «whoAmI». Потом сделайте экземпляр «obj» объекта (код ниже):
JavaScript
var MyObject = function() {}
MyObject.prototype.whoAmI = function() {
console.log(this === window ? «window» : «MyObj»);
}
var obj = new MyObject();
12345 | var MyObject = function() {}MyObject.prototype.whoAmI = function() { console.log(this === window ? «window» : «MyObj»); }var obj = new MyObject(); |
Предварительный шаг завершился, давайте начнем созодать нашу жизнь проще: так как нам необходимо получить доступ к не так давно установленному способу, и мы желаем упростить его, давайте сделаем ссылку на него и проверим, работает ли она подабающим образом.
JavaScript
obj.whoAmI(); // MyObj
var anotherMethod = obj.whoAmI;
anotherMethod(); // window
123 | obj.whoAmI(); // MyObjvar anotherMethod = obj.whoAmI;anotherMethod(); // window |
И мы получаем выход «window» заместо ожидаемого «MyObj».
Почему? ОК, когда мы создаем ссылку varanotherMethod = obj.whoAmI, способ whoAmI определен в глобальной области видимости. Глобальная область — это объект окна в браузере, потому ключевое слово this становится равным окну, а не экземпляру MyObject . Если мы желаем сделать правильную ссылку на способ экземпляра, то нам необходимо вызвать этот способ из самого объекта либо создать ссылку на объект, а не только лишь на способ объекта.
Верная ссылка будет смотреться так:
JavaScript
var obj = new MyObject();
var anotherObj = obj;
anotherObj.whoAmI() // MyObj
123 | var obj = new MyObject(); var anotherObj = obj;anotherObj.whoAmI() // MyObj |
либо же
JavaScript
obj.link = obj.whoAmI
obj.link(); // MyObj
12 | obj.link = obj.whoAmIobj.link(); // MyObj |
И мы получаем верный итог.
Трудности использования this
JavaScript стал достаточно сложным языком. this – это ключевое слово JavaScript, значение которого оценивается во время выполнения зависимо от контекста.
JavaScript
function myFunction() {
var myObject = {
objProperty: «some text»,
objMethod: function() {
alert(objProperty);
}
}
myObject.objMethod();
}
myFunction();
12345678910 | function myFunction() { var myObject = { objProperty: «some text», objMethod: function() { alert(objProperty); } } myObject.objMethod();} myFunction(); |
И мы получаем «ReferenceError: objProperty is not defined». Функции, определенные для объекта JavaScript, обращаются к свойствам этого объекта JavaScript и не могут применять ссылочный идентификатор this. Верный код смотрится так (не this =)):
JavaScript
function myFunction() {
var myObject = {
objProperty: «some text»,
objMethod: function() {
alert(this.objProperty);
}
}
myObject.objMethod();
}
myFunction();
12345678910 | function myFunction() { var myObject = { objProperty: «some text», objMethod: function() { alert(this.objProperty); } } myObject.objMethod();}myFunction(); |
Мысль ординарна: когда вызывается объект myObject.objMethod , он становится myObject во время вызова объекта objMethod. Когда мы определяем объект и желаем получить доступ к его свойствам и способам, нам поначалу необходимо получить доступ к самому объекту (звучит разумно). Но есть и оборотные ситуации, когда this употребляется некорректно.
JavaScript
Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(function() {
this.clearBoard();
}, 0);
}
123456 | Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(function() { this.clearBoard(); }, 0);} |
Возвращает нам еще одну ошибку: «undefined is not a function». Дело в том, что this в строке this.clearBoard() является необязательным, поэтому что когда вы вызываете setTimeout(), вы работаете с window.setTimeout(), потому вы вызываете объект окна в браузере. Окно объекта не имеет способа clearBoard(). Верная форма будет смотреться так:
JavaScript
Game.prototype.restart = function () {
var self = this;
this.clearLocalStorage();
this.timer = setTimeout(function() {
self.clearBoard(); // this = window
}, 0);
}
1234567 | Game.prototype.restart = function () { var self = this; this.clearLocalStorage(); this.timer = setTimeout(function() { self.clearBoard(); // this = window }, 0);} |
И пример, который существует с момента выпуска EcmaScript2015:
JavaScript
Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(() => {
this.clearBoard(); // this = Game
}, 0);
}
123456 | Game.prototype.restart = function () { this.clearLocalStorage(); this.timer = setTimeout(() => { this.clearBoard(); // this = Game }, 0);} |
Это также сделалось вероятным опосля ECMAScript 6. Когда мы используем функцию стрелки, мы остаемся в области деяния предшествующей функции, не создавая новейшую локальную область.
Утечки памяти, и что с сиим соединено
Давайте начнем с кода:
JavaScript
function myFunction() {
me = «You can’t touch me!»;
}
123 | function myFunction() { me = «You can’t touch me!»;} |
Это модифицированный пример из 2-ой главы данной статьи, видите разницу?
Если да, это здорово — вы понимаете, как объявлять ненадобные глобальные переменные, и относитесь пристально, когда дело касается скорости кода. Неувязка с сиим кодом состоит в том, что когда мы вызываем функцию myFunction, мы создаем ненадобную глобальную переменную, которая прячется в фоновом режиме до того времени, пока код не закончится. Глобальная переменная создается поэтому, что мы присваиваем значение переменной, которая не была объявлена ранее.
Хотя переменные не занимают много памяти, очень много данных, хранящихся в кэше, замедляют скорость загрузки странички и негативно влияют на скорость браузера в целом. Есть несколько вероятных решений. Используйте локальные переменные:
JavaScript
function myFunction() {
var me = «You can’t touch me!»;
}
123 | function myFunction() { var me = «You can’t touch me!»;} |
Используйте директиву «применять строго», которая не дозволяет вызывать необъявленную переменную:
JavaScript
function myFunction() {
“strict mode”
me = «You can’t touch me!»; //me is not defined
}
1234 | function myFunction() { “strict mode” me = «You can’t touch me!»; //me is not defined} |
Утечки памяти происходят, когда приложение хранит ненадобные данные, которые собиратель мусора не очищает во время работы. Другое событие, которое приводит к утечкам памяти, — это когда приложение употребляет память для выполнения определенной задачки: опосля выполнения задачки память освобождается, но время от времени это не так. Таковым образом, приложение хранит в памяти данные без предпосылки (потому что задачка выполнена).
Давайте разглядим иной код:
JavaScript
var trigger = document.getElementById(«trigger»);
var elem = document.getElementById(‘elementToDelete’);
trigger.addEventListener(«click», function() {
elem.remove();
});
12345 | var trigger = document.getElementById(«trigger»);var elem = document.getElementById(‘elementToDelete’);trigger.addEventListener(«click», function() { elem.remove();}); |
Когда мы исполняем код, elementToDelete удаляется из DOM. Но у нас все есть еще ссылка на него в прослушивателе, и в этот момент происходит утечка памяти, поэтому что выделенная память для объекта все еще употребляется. Решение последующее:
JavaScript
var trigger = document.getElementById(«trigger»);
trigger.addEventListener(«click», function() {
var elem = document.getElementById(‘elementToDelete’);
elem.remove();
});
12345 | var trigger = document.getElementById(«trigger»);trigger.addEventListener(«click», function() { var elem = document.getElementById(‘elementToDelete’); elem.remove();}); |
Тут elem объявлена снутри прослушивателя. Таковым образом, когда мы удаляем ее, путь к объекту обрезается и память освобождается.
Создатель: Anastasia Ovchinnikova
Редакция: Команда webformyself.
Источник