JavaScript — это ведущий в мире язык программирования, который можно использовать для веб-разработки, разработки мобильных приложений (PhoneGap, Appcelerator), серверной разработки (Node.js и Wakanda) и многого другого. JavaScript также является первым языком для многих новичков, входящих в мир программирования. Его можно использовать как для отображения простых диалоговых окон alert в браузере, так и для управления роботами через nodebot или nodruino. Разработчики, умеющие писать хорошо структурированный и высокопроизводительный код JavaScript, сегодня стали самыми востребованными специалистами на рынке труда.
В этой статье я поделюсь некоторыми советами, приёмами и лучшими практиками JavaScript. За небольшими исключениями, они применимы как к браузерным движкам JavaScript, так и к серверным интерпретаторам JavaScript.
Пример кода в этой статье был протестирован на последней версии Google Chrome 30 (V8 3.20.17.15).
1. Всегда используйте при первом присваивании переменнойvarkeyword
Если переменной присваивается значение без её объявления, она по умолчанию становится новой глобальной переменной. Старайтесь не использовать глобальные переменные.
2. Используйте===вместо==
==и!=Оператор автоматически преобразует типы данных, когда это необходимо. Но===и!==не делайте этого. Они сравнивают одновременно и значение, и тип данных, что также делает их [быстрее], чем==и!=, 0, false, NaN и пустые строки — все они вычисляются как false в логическом контексте
[10] === 10 // is false [10] == 10 // is true '10' == 10 // is true '10' === 10 // is false [] == 0 // is true [] === 0 // is false '' == false // is true but true == "a" is false '' === false // is false
3, undefined、null, 0, false, NaN и пустые строки — все они вычисляются как false в логическом контексте
4. Используйте точку с запятой в конце строк
Правда о точках с запятой в JavaScript5. Используйте конструкторы объектов。
5. Используйте конструкторы объектов
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
var Saad = new Person("Saad", "Mousliki");
6. Будьте осторожны сtypeof、instanceofиcontructor
typeofтакже возвращаетtypeof null, большинство типов объектов (Array, Date и т. д.) также возвращаютobject: внутреннее свойство prototype, может быть перезаписано кодомobjectcontructor: оператор JavaScript, ищет конструкторы в цепочке прототипов, возвращает, если найденinstanceof, иначе возвращаетtruefalse
var arr = ["a", "b", "c"]; typeof arr; // 返回 "object" arr instanceof Array // true arr.constructor(); //[]
7. Используйте самовызывающиеся функции
Функция выполняется автоматически сразу после создания, обычно называется самовызывающейся анонимной функцией или немедленно вызываемым функциональным выражением (IIFE). Формат следующий:
(function(){
// 置于此处的代码将自动执行
})();
(function(a,b){
var result = a+b;
return result;
})(10,20)
8. Получите случайный элемент из массива
var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119]; var randomItem = items[Math.floor(Math.random() * items.length)];
9. Получите случайное число в заданном диапазоне
Эта возможность особенно полезна при генерации фиктивных данных для тестирования, например чисел зарплаты в заданном диапазоне.
var x = Math.floor(Math.random() * (max - min + 1)) + min;
10. Сгенерируйте массив чисел от 0 до заданного значения
var numbersArray = [] , max = 100; for( var i=1; numbersArray.push(i++) < max;); // numbers = [1,2,3 ... 100]
11. Сгенерировать случайную буквенно-цифровую строку
function generateRandomAlphaNum(len) {
var rdmString = "";
for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
return rdmString.substr(0, len);
}
12. Перемешать порядок числового массива
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){ return Math.random() - 0.5});
/* numbers 数组将类似于 [120, 5, 228, -215, 400, 458, -85411, 122205] */
Здесь используется встроенная функция сортировки массивов JavaScript. Лучший способ — использовать специальный код (например, алгоритм Фишера — Йетса). См. обсуждение на StackOverflowэто обсуждение。
13. Удалить пробелы из строки
В Java, C#, PHP и других языках есть специальные функции обрезки строк, но в JavaScript их нет. Вы можете использовать следующий код, чтобы добавить дляStringобъекта atrimфункцию:
String.prototype.trim = function(){return this.replace(/^\s+|\s+$/g, "");};
Новые движки JavaScript уже имеютtrim()нативные реализации.
14. Объединение массивов
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
15. Преобразовать объект в массив
var argArray = Array.prototype.slice.call(arguments);
16. Проверить, является ли это числом
function isNumber(n){
return !isNaN(parseFloat(n)) && isFinite(n);
}
17. Проверить, является ли это массивом
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
Но еслиtoString()если метод был переопределён, это не сработает. Также можно использовать следующий метод:
Array.isArray(obj); // its a new Array method
Если в браузере не используются фреймы, можно также использоватьinstanceof, но если контекст слишком сложный, это тоже может не сработать.
var myFrame = document.createElement('iframe');
document.body.appendChild(myFrame);
var myArray = window.frames[window.frames.length-1].Array;
var arr = new myArray(a,b,10); // [a,b,10]
// myArray 的构造器已经丢失,instanceof 的结果将不正常
// 构造器是不能跨 frame 共享的
arr instanceof Array; // false
18. Получите максимальное и минимальное значения в массиве
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; var maxInNumbers = Math.max.apply(Math, numbers); var minInNumbers = Math.min.apply(Math, numbers);
19. Очистите массив
var myArray = [12 , 222 , 1000 ]; myArray.length = 0; // myArray will be equal to [].
20. Не удаляйте напрямую из массиваdeleteилиremoveэлементов
Если вы напрямую применяете к элементам массиваdelete, это на самом деле не удаляет, а устанавливает элемент вundefined. Чтобы удалить элементы массива, следует использоватьsplice。
Никогда:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 delete items[3]; // return true items.length; // return 11 /* items 结果为 [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
Вместо этого:
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 items.splice(3,1) ; items.length; // return 10 /* items 结果为 [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119]
При удалении свойств объекта можно использоватьdelete。
21. Используйтеlengthсвойство для усечения массива
В предыдущем примере использованиеlengthсвойства опустошило массив. Вы также можете использовать его для усечения массива:
var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ]; myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].
В то же время, если сделатьlengthсвойство больше, длина массива увеличится, и он будет использоватьundefinedдля заполнения новых элементов.lengthявляется записываемым свойством.
myArray.length = 10; // the new array length is 10 myArray[myArray.length - 1] ; // undefined
22. Используйте логические И/ИЛИ в условиях
var foo = 10; foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething(); foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething();
Логическое ИЛИ также можно использовать для установки значений по умолчанию, например значений по умолчанию для параметров функции.
function doSomething(arg1){
arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set
}
23. Сделайтеmap()методы функций перебирают данные
var squares = [1,2,3,4].map(function (val) {
return val * val;
});
// squares will be equal to [1, 4, 9, 16]
24. Сохранять заданное количество знаков после запятой
var num =2.443242342; num = num.toFixed(4); // num will be equal to 2.4432
Обратите внимание, чтоtoFixec()возвращается строка, а не число.
25. Проблемы вычислений с плавающей запятой
0.1 + 0.2 === 0.3 // is false 9007199254740992 + 1 // is equal to 9007199254740992 9007199254740992 + 2 // is equal to 9007199254740994
Почему? Потому что 0.1+0.2 равно 0.30000000000000004. Числа JavaScript построены в соответствии со стандартом IEEE 754 и внутренне все являются 64-битными представлениями с плавающей запятой. Подробнее см.Как числа кодируются в JavaScript.
Вы можете использоватьtoFixed()иtoPrecision()чтобы решить эту проблему.
26. Проверка свойств объекта с помощью цикла for-in
Следующее использование может предотвратить перебор свойств прототипа объекта.
for (var name in object) {
if (object.hasOwnProperty(name)) {
// do something with name
}
}
27. Оператор запятая
var a = 0; var b = ( a++, 99 ); console.log(a); // a will be equal to 1 console.log(b); // b is equal to 99
28. Временное сохранение переменных для вычислений и поиска
В селекторах jQuery можно временно сохранять целые DOM-элементы.
var navright = document.querySelector('#right');
var navleft = document.querySelector('#left');
var navup = document.querySelector('#up');
var navdown = document.querySelector('#down');
29. Проверяйте входящие данные заранееisFinite()parameters
isFinite(0/0) ; // false
isFinite("foo"); // false
isFinite("10"); // true
isFinite(10); // true
isFinite(undefined); // false
isFinite(); // false
isFinite(null); // true,这点当特别注意
30. Избегайте использования отрицательных чисел в качестве индексов массивов
var numbersArray = [1,2,3,4,5];
var from = numbersArray.indexOf("foo") ; // from is equal to -1
numbersArray.splice(from,2); // will return [5]
Обратите внимание, что параметр index, передаваемый вspliceне должен быть отрицательным; если он отрицательный, элементы будут удалены с конца массива.
31. Используйте JSON для сериализации и десериализации
var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} };
var stringFromPerson = JSON.stringify(person);
/* stringFromPerson 结果为 "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */
var personFromString = JSON.parse(stringFromPerson);
/* personFromString 的值与 person 对象相同 */
32. Не используйтеeval()или конструкторы функций
eval()и конструктор функции (Functionconsturctor) имеют значительные накладные расходы; каждый раз, когда они вызываются, движку JavaScript приходится преобразовывать исходный код в исполняемый код.
var func1 = new Function(functionCode); var func2 = eval(functionCode);
33. Избегайте использованияwith()
Использованиеwith()может добавлять переменные в глобальную область видимости, поэтому если есть другие переменные с таким же именем, это вызовет путаницу, и значения также будут перезаписаны.
34. Не используйте for-in для массивов
Избегайте:
var sum = 0;
for (var i in arrayNumbers) {
sum += arrayNumbers[i];
}
Вместо этого:
var sum = 0;
for (var i = 0, len = arrayNumbers.length; i < len; i++) {
sum += arrayNumbers[i];
}
Ещё одно преимущество в том, что,iиlenобе переменные находятсяforв первом объявлении цикла, и обе инициализируются только один раз, что быстрее, чем следующий подход:
for (var i = 0; i < arrayNumbers.length; i++)
35. Передавайте вsetInterval()иsetTimeout()используйте функцию вместо строки, когда
Если передатьsetTimeout()иsetInterval()строку, они будут использовать метод, подобныйevalчтобы преобразовать её, что, безусловно, будет медленнее, поэтому не используйте:
setInterval('doSomethingPeriodically()', 1000);
setTimeout('doSomethingAfterFiveSeconds()', 5000);
Вместо этого используйте:
setInterval(doSomethingPeriodically, 1000); setTimeout(doSomethingAfterFiveSeconds, 5000);
36. Используйтеswitch/caseвместо большого стекаif/else
Когда у условия больше двух ветвей, используйтеswitch/caseэто быстрее, элегантнее и лучше для организации кода. Конечно, если ветвлений больше 10, не используйтеswitch/caseэто.
37. Вswitch/caseиспользуйте числовые диапазоны в
На самом деле,switch/caseвcaseусловии, это также можно записать так:
function getCategory(age) {
var category = "";
switch (true) {
case isNaN(age):
category = "not an age";
break;
case (age >= 50):
category = "Old";
break;
case (age <= 20):
category = "Baby";
break;
default:
category = "Young";
break;
};
return category;
}
getCategory(5); // 将返回 "Baby"
38. Используйте объект как прототип другого объекта
Следующим способом заданный объект можно передать как параметр, чтобы создать новый объект, использующий его в качестве прототипа:
function clone(object) {
function OneShotConstructor(){};
OneShotConstructor.prototype = object;
return new OneShotConstructor();
}
clone(Array).prototype ; // []
39. Функции преобразования полей HTML
function escapeHTML(text) {
var replacements= {"<": "<", ">": ">","&": "&", "\"": """};
return text.replace(/[<>&"]/g, function(character) {
return replacements[character];
});
}
40. Не используйте try-catch-finally внутри циклов
В try-catch-finally часть catch при выполнении присваивает исключение переменной, и эта переменная создаётся как новая переменная в области видимости времени выполнения.
Избегайте:
var object = ['foo', 'bar'], i;
for (i = 0, len = object.length; i <len; i++) {
try {
// do something that throws an exception
}
catch (e) {
// handle exception
}
}
Вместо этого:
var object = ['foo', 'bar'], i;
try {
for (i = 0, len = object.length; i <len; i++) {
// do something that throws an exception
}
}
catch (e) {
// handle exception
}
41. Обязательно устанавливайте тайм-аут при использовании XMLHttpRequests
Когда XMLHttpRequests выполняются и долго не получают ответа (например, при возникновении проблем с сетью), соединение следует прервать. Это можно сделать с помощьюsetTimeout()чтобы сделать это:
var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
clearTimeout(timeout);
// do something with response data
}
}
var timeout = setTimeout( function () {
xhr.abort(); // call error callback
}, 60*1000 /* timeout after a minute */ );
xhr.open('GET', url, true);
xhr.send();
Также учтите, что не следует инициировать несколько XMLHttpRequests одновременно.
42. Обработка тайм-аутов WebSocket
Обычно после создания соединения WebSocket, если в течение 30 секунд нет активности, сервер завершает соединение по тайм-ауту, а брандмауэры также могут завершать соединения, у которых нет активности в течение определённого периода.
Чтобы это предотвратить, можно через регулярные интервалы отправлять на сервер пустое сообщение. Это достигается с помощью следующих двух функций: одна — для поддержания соединения активным, а другая — специально для завершения этого состояния.
var timerID = 0;
function keepAlive() {
var timeout = 15000;
if (webSocket.readyState == webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
cancelTimeout(timerId);
}
}
keepAlive()Функцию можно разместить в конце WebSocket-соединенияonOpen()метод,cancelKeepAlive()и разместить вonClose()самом конце метода.
43. Всегда помните, что примитивные операторы быстрее вызовов функций; используйте VanillaJS
Например, обычно не делайте так:
var min = Math.min(a,b); A.push(v);
Это можно заменить на следующее:
var min = a < b ? a : b; A[A.length] = v;
44. Обращайте внимание на структуру кода во время разработки, а перед публикацией проверяйте и сжимайте код JavaScript
Не забывайте использовать инструмент форматирования кода при написании кода. Используйте JSLint (инструмент проверки синтаксиса) и минифицируйте код перед публикацией (например, с помощью JSMin). Примечание: сейчас для минификации кода обычно рекомендуется UglifyJS (https://github.com/mishoo/UglifyJS2)
45. JavaScript обширен и глубок; вот несколько хороших ресурсов для обучения
- Ресурс Code Academy: http://www.codecademy.com/tracks/javascript
- Автор — Marijn HaverbekeEloquent JavaScript:http://eloquentjavascript.net/
- Автор — John ResigAdvanced JavaScript:http://ejohn.org/apps/learn/
Источник: http://www.codeceo.com/article/javascript-45-tips.html