Ознакомимся с несколькими полезных приемами программирования в JavaScript, вместо которых мы часто пишем намного более громоздкие конструкции.
Конвертирование переменных
Как ни странно, но иногда для конвертирования переменных одного типа в другой используют конструкторы объектов типа Array() или Number(). На самом деле правильнее и лучше (с точки зрения производительности) использовать примитивные типы данных:
var myVar = "3.14159",
str = ""+ myVar,// в стринг (string)
int = ~~myVar, // в интеджер (integer)
float = 1*myVar, // во флоат (float)
bool = !!myVar, // в булен - все непустые строки и числа кроме 0 будут true
array = [myVar]; // в массив
Конвертирование в даты (new Date(myVar)) и регулярные выражения (new RegExp(myVar)) нужно делать с использованием конструкторов. Всегда используйте структуру /регулярное_выражение/флаги при создании регулярных выражений.
Округление числа до нужной точности после запятой:
1.234.toFixed(2)
В результате получим число 1.23
Замена всех вхождений подстроки в строку
Часто случается, что нужно заменить все вхождения какой-то строки в другую строку. Вместо громоздких конструкций лучше всего делать так:
var str = "foobarfoobar";
str.replace(/foo/g,"xxx");
// в итоге получиться str = "xxxbarxxxbar";
Передача аргументов функции
В JavaScript действуют следующие правила передачи аргументов функции:
Аргументы примитивных типов - передаются в функцию по значению. Иными словами, формальным аргументам присваиваются значения фактических аргументов на момент вызова и, если даже операторы в теле функции изменят значение какого-либо аргумента, то это изменение не коснется переменной, чье значение передавалось в качестве аргумента. Например:
function setBrowser(browser) {
browser = "Internet Explorer";
}
var myBrowser = "Netscape Navigator";
setBrowser(myBrowser); // объект myBrowser передается функции
alert(myBrowser); // выводит "Netscape Navigator"
Объекты (и встроенные, и определенные пользователем) передаются по ссылке. Это означает, что все изменения свойств объекта в теле функции производятся непосредственно в самом объекте, а не в его локальной копии и, следовательно, сохраняются после возврата из функции. Например:
function setBrowser(browser) {
browser.name = "Internet Explorer";
browser.version = "5.5";
}
var myBrowser = {
name:"Netscape Navigator",
version:"4.7"
};
setBrowser(myBrowser); // объект myBrowser передается функции
alert(myBrowser.name); // выводит "Internet Explorer"
Необязательные аргументы функции
Когда у какой-то функции есть как обязательные, так и необязательные аргументы, то передавать проще только один объект вместо нескольких обычных аргументов:
function doSomething() {
// Оставляем аргументы, если ничего не передано
if (!arguments[0]) {
return false;
}
var oArgs = arguments[0]
arg0 = oArgs.arg0 || "",
arg1 = oArgs.arg1 || "",
arg2 = oArgs.arg2 || 0,
arg3 = oArgs.arg3 || [],
arg4 = oArgs.arg4 || false;
}
doSomething({
arg1 : "foo",
arg2 : 5,
arg4 : false
});
Замыкания
Про замыкания написано много, но мало где найдешь пример, демонстрирующий неочевидные нюансы при работе с объектами. Итак, имеем объект:
var mydata = [
{
name : "foo"
},
{
name : "bar"
}
];
Пробежимся по объекту и заполним массив новыми объектами (взяв данные у объекта выше):
var result = [];
for (var i = 0; mydata.length > i; i++) {
var my = mydata[i];// берем объект из массива
var info = {// создаем объект с функцией, которая будет возвращать имя объекта
showName: function () {
return my.name;
}
};
result.push(info);
}
console.log(result[0].showName());// неправильно bar (лично я ожидал foo)
console.log(result[1].showName());// правильно bar
Ошибка просиходит потому, что мы забыли заинитить переменную в функции showName, поэтому согласно поведению LexicalEnvironment, значение будет искаться в вышестоящем [[Scope]].
Так давайте передадим аргумент в функцию, а не будем использовать значение из [[Scope]].
...
showName: function (my) {
return my.name;
}(my)
...
проверим результат:
console.log(result[0].showName);// правильно foo console.log(result[1].showName);// правильно bar
* ОБРАТИТЕ ВНИМАНИЕ: теперь поле showName формально перестало быть функцией (пока не разобрался почему), но на практике, вы можете поместить в эту все еще функцию любой вызов, и он выполнится.
Хочется добавить, что можно замыкать данные на любом уровне, например:
...
var closuredData = function(my){
var info = {// создаем объект с функцией, которая будет возвращать имя объекта
showName: function () {
return my.name;
}
};
result.push(info);
}(my);
...
и теперь, наш ключ, снова является классической функцией:
console.log(result[0].showName());// правильно foo console.log(result[1].showName());// правильно bar
Всем удачи.
Комментарии
Комментариев пока нет.