47 posts tagged

разработка

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

/core.php, line 2
Error 2: Use of undefined constant k - assumed 'k' (this will throw an Error in a future version of PHP)

Later Ctrl + ↑

С кодом будь строг. Интерпретатор

Строгий контроль написания кода уменьшает количество потенциальных ошибок. javascript допускает многие вольности, при том такие, которые могут породить трудно обнаруживаемые ошибки. Тут на помощь приходят редакторы и интерпретаторы. На уровне редакторов есть несколько инструментов, статического анализа кода, а со стороны браузеров доступен строгий режим выполнения javascrip кода.

Use strict

Ниже — примеры того, где строгий режим генерирует ошибки (полное описание отличий строгого режима). Надо отметить, что генерация ошибок происходит на этапе чтения исходного файла. Это значит, что функции, объявленные в нестрогой области видимости будут без проблем вызваны из «строгих функций». Так же не рекомендуется использовать строгий режим глобально, потому что вероятнее всего он сломает 3-d party код.

Нельзя присвоить значение необъявленной переменной. Код ниже в строгом режиме вместо создания глобальной переменной выдаст ошибку.
// Нестрогое поведение
function f () {
	a = 10;
}
f();
// Неожиданная глобальная переменная
console.log(a); // 10


// Строгое поведение
function f () {
	'use strict';
	a = 10;
}
f(); // ошибка

Запрещено дублирование имен свойств объекта.
(function () {
	var obj = {
		prop : true,
		prop : false
	}

	console.warn(obj); // {prop:false}
}());

(function () {
	'use strict';

	var obj = {
		prop : true,
		prop : false
	}

	console.warn(obj); // error
}());

Объект arguments — неизменяемый. Проблема заключается, в том, что изменяя arguments, изменение коснутся и аргументов, связанных с переменными, и самое неприкольное то, что примитивные значения тоже изменятся.
function f (a, b) {
	arguments[0] = 10;
	console.log(a, b);
}

f(1, 99); // 10, 99

Запрещено использование arguments.callee, и arguments.callee.caller. Говорят, что из-за наличия такого кода, интерпретатор не может оптимизировать код. Вместо этих конструкций рекоммендуется использовать named function expression.
(function waiter () {
	if (condition()) {
		action();
	} else {
		setTimeout(waiter, 50); // используем имя вместо arguments.callee
	}
}());
2012   по-русски   разработка

Ленивые вычисления в javascript

Ленивые, отложенные вычисления — такой подоход, когда значения вычисляются только тогда, когда в них возникает потребность, при этом есть возможность не вычислять это значение повторно при последующих вызовах функции. В javascript этот подход можно реализовать с помощью замыканий и переопределения функции изнутри самой себя.
function func_name () {
	var variable_foo,
		variable_bar;

	variable_foo = get_foo();
	variable_bar = get_bar();
	func_name = function () {
		return variable_foo + variable_bar;
	};
	return func_name.apply(this, arguments);
}
Фишка заключается в том, что значения variable_foo и variable_bar будут вычислены только при первом вызове функции. При этом-же вызове функция переопределит себя, захватывая scope с вычисленными переменными и себя-же родимую вызовет (при этом корректно сохраняя this, возвращаемое значение, а так же переданные аргументы).

Этот подход сработает и для методов:
var obj;

obj = {};
obj.method = function () {
	var variable_foo,
		variable_bar;

	variable_foo = get_foo();
	variable_bar = get_bar();
	this.method = function () {
		return variable_foo + variable_bar;
	};
	return this.method.apply(this, arguments);
}
Такие манипуляции дадут выгоду по производительности в случае, если метод или функция может быть не вызвана. В этом случае выигрыш составляет время вычисления кешируемых переменных. Или же случаи, когда функция вызывается два и более раз. В этом случае выигрыш составит время вычислений переменных помноженное на количество вызовов.

Из минусов: зависимость от имени функции или метода. Слишком просто будет допустить ошибку. Во избежание залепил сниппет для sublimetext2, который расскрывается в следующее
// srv
function_name = function () {

};
return function_name.apply(this, arguments);
(этот сниппет можно найти на gihub).
2012   по-русски   разработка

Javascript и common lisp синонимы

Мой второй подход к снаряду (practical common lisp). Синонимические конструкции из javascript и common lisp для самоободрения.
var o = (function () {
    var count = 0;

    return [function () {
        return count += 1;
    }, function () {
        return count -= 1;
    }, function () {
        return count;
    }];
}());
(defparameter *o* (let ((count 0))
					(list 
					 #'(lambda () (incf count))
					 #'(lambda () (decf count))
					 #'(lambda () count))))
2012   по-русски   разработка

Асинхронный итератор

При работе с googlemaps столкнулся с проблемой, когда большое количество маршрутов (более 20) при одновременной отрисовке принеприятно тормозило интерфейс. При это последний firefox тормозил сильнее, чем internet explorer. Для обхода проблемы решил, что если единовременно надо отрисовать больше, чем 15 маршрутов, я буду рисовать их с периодичностью в 50 мс. То есть между вызовами функций отрисовки будет проходит не менее 50мс (gist).
function iterate_async (arr, callback, timeout) {
	var index;

	index = 0;
	(function run () {
		if (index < arr.length) {
			setTimeout(function () {
				callback.call(arr, arr[index], index, arr);
				index += 1;
				run();
			}, timeout || 50);
		}
	}());
}
Из нюансов:
  • первый вызов синхронный
  • this в обработчике ссылается на обрабатываемый массив
  • обработчик получает аргументами элемент массива, индекс обрабатываемого элемента, сам обрабатываемый массив
  • если не указано явное время между вызовами обработчиков, то оно устанавливается в 50мс
И пример вывода элементов списка с вызовом обработчика через каждые 99мс:
var arr = ['masha','nadya', 'elena'];
iterate_async(arr, function (el, index, arr) {
    console.log(el + ' is #' + (index + 1));
}, 500);
2012   по-русски   разработка

javascript сниппеты для sublimetext2

Дошли руки оформить коллекцию javascript сниппетов для sublimetext2. Как человеку, работающему с кодом, мне хочется как можно меньше набирать текст, меньше тратить телодвижений на превращение мысли в код.

Установка вручную

  1. скачать архив с github
  2. распаковать в папку с package-ами (в редакторе: Preferences – Browse Packages...)

Установка через package control

  1. В sublimetext2 выполнить в консоли “Package Control: Add Repository”
  2. В поле ввода вставить урл https://github.com/podgorniy/js-snippets-st2
  3. Теперь сниппеты можно устанавливать как любой другой плагин из Package Control (в консоли Package Control: Install Package – js-snippets-st2)
Преимущество последнего: обновление сниппетов, автоматически при обновлении репозитория.

Субъективные переживания

Свойства сниппетов для sublimetext2, что меня порадовали:
  • сниппет появляется в автокомплите
  • сниппет доступен их командной строки (где его можно искать по описанию)
  • сниппет не статический, доступно нечто вроде ветвления (об это ниже)
Про “ветвление” (уверен, что этому явлению есть научное название). Стандартный сниппет get разворачивается в нечто следующее: getElementsByTagName(‘‘) при этом символ “T” выделен. Если начать набирать I, то развертка сниппета превратится в getElementById(‘‘). Это революция: зачем делать два отдельных сниппета для таких схожих методов, если можно обойтись одним? Попробуйте, с таким подходом код становится набирать на 55% приятнее и на 50% быстрее. Я дал себе обещание научиться писать подобные сниппеты и сдержал его. Позже расширил коллекцию частоупотребляемыми методами.

Tabstops указаны символом | (последовательность не указана, определяйте ее экспериментальным путем)
Однословные
  • a – arguments
  • de – debugger
  • d – document
  • l – location
  • p – prototype
  • w – window
  • q – querySelectorAll(‘‘)
Логгирование
  • cl – console.log();
  • cw – console.warn();
  • ci – console.info();
  • ct – console.timeStamp(‘‘);
Анонимщина
// sif
;(function () {
	|
}());

//sifs
;(function () {
	'use strict';

	|
}());

Теперь хитрые (с ветвлением, текстом по умолчанию и кучей tabstops)
Хитрые
  • set – setTimeout(function () {}, 50); по умолчанию стоит setTimeut, но достаточно начать набирать I, как сниппет превратится в setInerval (при этом есть возможность изменить время таймаута, вместо анонимной функции указать именованную. Последняя остановка внутри анонимной функции)
  • clr – clearTimeout(); так же позволяет очищать интервалы
//for
for (i = 0; i < arr.length; i += 1) {
	arr[i]
}
Цикл (стандартные ужасны) можно подменять имя массива, имя счетчика. Подразумевается, что счетчик уже объявлен (да, я объявляю переменные в начале функции)
  • ’ – ’ + + ’ крайне удобная вещь для быстрой вставки значений в строки.
2012   по-русски   разработка

Трюк с очисткой всех интервалов и таймаутов

Перечитывал JavaScript-Garden, в секции таймеров есть следующий код:
// удаляем "все" таймауты
for(var i = 1; i < 1000; i++) {
    clearTimeout(i);
}
Авторы утверждают, что не все таймауты могут быть завершены этим циклом, и это утверждение не вызывает сомнений. Но способ остановить все таймауты (и интервалы) все-же есть. Фишка в том, что функции setTimeout и setInterval возвращают id таймера, который при каждом вызове увеличивается на 1 (и для интервалоц и таймаутов). Таким образом, если создать интервал прямо перед очисткой всех интервалов, то его id будет наибольшим. Все, кто имеет меньший id будут очищены:
// удаляем все таймауты
var max_id;

max_id = setTimeout(function () {});
while (max_id--) {
    clearTimeout(max_id);
}
2012   по-русски   разработка

Замена всех вхождений подстроки

Ничего лучше, чем преобразование подстроки в регулярку с флагом g, не нашел (может вы подскажите). Идея заключается в том, чтобы экранировать все служебные символы регулярок перед проведением замены.
function replace_string_occurances (src_string, string_to_replace, replace_rule) {
	var escaped_string,
		reg;

	escaped_string = string_to_replace.replace(/[\(\)\[\]\\\.\^\$\|\?\+]/g, '\\$&');
	reg = new RegExp(escaped_string, 'g');
	return src_string.replace(reg, replace_rule);
}

Если же служебные символы не экранировать, то [.] превращается в корректное регулярное выражение. А так, код ниже отработает корректно:
replace_string_occurances('[.]_[.]', '[.]', '[*]'); // [*]_[*]
2012   по-русски   разработка
Earlier Ctrl + ↓