Показаны сообщения с ярлыком javascript. Показать все сообщения
Показаны сообщения с ярлыком javascript. Показать все сообщения

среда, 29 июля 2015 г.

RegExp в Presto

Opera в своё время прославилась тем, что не поддерживала compile() у регулярных выражений. Дело было в движке Presto (которые почему-то не желает их копилировать).

И вот случилось - Opera переехала на Blink. Теперь compile() поддерживается.... но не в Opera Mini, которая как была на Presto, там так и остаётся.

понедельник, 1 июня 2015 г.

Показать в JavaScript alert без остановки таймера

Вообще, использовать стандартный JavaScript alert даже для отладки - плохая идея. Для сообщений есть отличные окошки из Bootstrap JS или jQueryUI, для отладочной информации - console.log.

Но иногда нужно написать окошко очень-очень быстро. Например, сдать бета-версию приложения, а окошко потом переделать.

В браузерах, основанных на WebKit (Chrome, Safari, JavaFX WebEngine) открытый alert считается чрезвычайным событием и останавливает все таймеры своей нити. Поэтому показывать его надо в отдельной нити, вот так:

function showMessage(text){
  setTimeout(function() { alert(text); }, 1);
}

среда, 29 апреля 2015 г.

receiving GET params of url - 4

Оказывается, все параметры, передаваемые в URL get-запросом. лежат в свойстве location.search. Как-то так: "?foo=boo".

А значит, старый код можно переписать ещё раз:

$.extend({
    getUrlStr : function() {
        //used for unit test
        return location.search.substr(1);
    },
    getUrlVars : function(){
        var vars = {},
            hashes = this.getUrlStr();
        if(!hashes)
            return {};
        hashes = hashes.split('&');
 for(var i = 0, len = hashes.length; i < len; i++) {
  var hash = hashes[i].split('=');
  vars[hash[0]] = hash[1];
 }
 return vars;
     },
     urlVars : null,
     getUrlVar : function(key) {
 if(!key) return null;
 if(!this.urlVars) this.urlVars = this.getUrlVars();
 return (this.urlVars[key] !== undefined) ? this.urlVars[key] : null;
     },
});

четверг, 23 апреля 2015 г.

Д. Босуэлл, Т. Фаучер - Читаемый код или программирование как искусство

Небольшая книжка, в которой много полезных мелочей.

Например, более точные варианты названий для типичных функций:

send - deliver; dispatch; announce; distribute; route
find - search; extract; locate;recover
start - launch; create; begin; open
make - create; setup; build; generate; compose; new

Именованные интераторы для циклов (ui лучше, чем просто i).

Дополнительные постфиксы - size_mb, html_utf луче, чем size и html.

first/last - это включающие, а begin/end - исключающие границы.

Пометы в комментах:

TODO - задумано, но не сделано.
FIXME - известно, что есть проблема
HACK - неэлегантное решение проблемы
XXX - серьёзная проблема

Уже второе недоумение насчёт цикла do-while (которые непонятно, зачем нужен).

Разоблачён миф о том, что из функции должен быть только один выход. Он тянется из чистого C, где нередко забывали вычистить память перед выходом. Но c тех пор появились исключения, деструкторы и очистка мусора. А в C простительно писать goto cleanup;

Вообще, если удаётся уменьшить количество отступов, - это хорошо.

Запутывают код: многопоточность, обработчики сигналов/прерываний, исключения, указатели на функции и анонимные функции, виртуальные методы.

В JavaScript и Python переменная, объявленная внутри цикла, будет видна и снаружи. Вообще, область видимости переменных надо сужать. А самые лучшие переменные - константы, поэтому лучше всего менять их один раз.

Переменные объявлять где используются, а не в начале блока. Объявлять всё в начале блока - дурная традиция из Pascal и раннего C (хотя в C99 уже разрешили объявлять где угодно).

Также есть приятные куски кода:

Макрос для C++, чтобы убрать warning для неопределённого конструктора копирования или оператора присваивания.

#define DISALLOW_COPY_AND_ASSIGN(ClassName) \
  ClassName(const ClassName&); \
  void operator=(const ClassName&);

И потом писать:
class ClassName {
  private:
     DISALLOW_COPY_AND_ASSIGN(ClassName);
     ...
  public:
     ...
};

понедельник, 13 апреля 2015 г.

Параметры по умолчанию в JavaScript

Загружаем необязательные опции функции из указанных в default_options.

Для методов вида doSomething(main_data, options), где options не обязательны.


var JsOptionsHelper = (function(){
  function doLoadOptions(default_options, options){
    var result_options = {};
    if(!options) {
      for(var opt_key in default_options)
        result_options[opt_key] = default_options[opt_key];
    } else {
      for(var opt_key in default_options)
        result_options[opt_key] = (options[opt_key] !== undefined) ? options[opt_key] : default_options[opt_key];
    }
    return result_options;
  }
  return {
    loadOptions : doLoadOptions
  };
})();


понедельник, 30 марта 2015 г.

JavaScript charset в браузере

Согласно стандарту HTML5, стандартная кодировка страницы - UTF-8. А вот с JavaScript всё сложнее.

Пусть у нас есть какой-то JSON. Напишем функцию, которая его возвращает:

function getOutlineJson() {
  return {
      "title" : "Элемент1"
  };
}

Сохраняем в отдельный файл, привязываем через <script>. Пытаемся вывести в консоль:


document.addEventListener('DOMContentLoaded', function() {
  console.log(getOutlineJson());
});

В консоли будет JSON с полями на неведомом языке. Хотя, как подтверждает view.encoding() в консоли Sublime, все файлы - в UTF-8.

А если добавить вывод чего-то кириллического прямо на экран?

document.addEventListener('DOMContentLoaded', function() {
  console.log("проверка консоли");
  console.log(getOutlineJson());
});

Внезапно, кодировка починилась. Видимо, кодировка выставляется по первому вызову.

Лечится мета-тегом:

<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

Проверено в Firefox и Chrome.

среда, 25 марта 2015 г.

eval в JavaScript

eval в JavaScript с отложенным выполнением:

var JsEvaluator = (function(){
  var errors = {
    WRONG_SYNTAX : "Синтаксическая ошибка в выражении \"%SOURCE%\"",
    NON_SYNTAX : "Ошибка %ERROR_TITLE% при разборе выражения \"%SOURCE%\""
  };

  function null_func() { return null; }

  return {
    checkedEval : function(str_to_eval){
      if(!str_to_eval)
        return null_func;
      var trimmed_str = str_to_eval.trim();
      if(!trimmed_str)
        return null_func;
      try {
        var result = eval(trimmed_str);
        if(result === undefined)
          return null_func;
      } catch(e) {
        var error_text = (!(e instanceof SyntaxError)) ?
                          errors.WRONG_SYNTAX.replace(/%SOURCE%/, trimmed_str) :
                          errors.NON_SYNTAX.replace(/%ERROR_TITLE%/, e.name).replace(/%SOURCE%/, trimmed_str);
        console.error(error_text);
        return null_func;
      }
      return function() { return eval(trimmed_str); };
    }
  };
})();

Возвращать именно функцию может быть полезно, если выражение в eval завязано на какую-то внешнюю переменную. Например, в str_to_eval у нас условие: "Param1 > 10". Понятно, что его надо выполнить в момент проверки, а не инициализации. Поэтому выполнение в примере отложено.

Для eval выполняется правило последней строки, пришедшее в Ruby и R из Fortran - eval возвращает значение, которое вернула последняя выполненная строка переданного ему выражения. Это может быть в т.ч. строка с числом:
eval("1;2;4")
> 4

или даже со строковой константой:

eval("'boo'")
> "boo"

Как вариант, можно отказаться от ошибок и понимать "неправильный" JavaScript как строковую константу:

var JsEvaluator = (function(){
  function null_func() { return null; }
  return {
    checkedEval : function(str_to_eval){
      if(!str_to_eval)
        return null_func;
      var trimmed_str = str_to_eval.trim();
      if(!trimmed_str)
        return null_func;
      try {
        var result = eval(trimmed_str);
        if(result === undefined)
          return null_func;
      } catch(e) {
        return function() { return str_to_eval; };
      }
      return function() { return eval(trimmed_str); };
    }
  };
})();

вторник, 17 марта 2015 г.

undefined в JavaScript и receiving GET params of url - 3

В чём разница между typeof boo == "undefined" и boo === undefined в JavaScript?

Они делают почти одно и то же. И у boo === undefined есть плюсы и минусы:

Плюсы

+ И в "undefined", и в undefined можно допустить опечатку. Но во втором случае браузер немедленно заругается.
+ Такое сравнение подходит и для "пустых" параметров функции, и для несуществующих свойств объектов.

Минусы

- Если переменная boo просто нигде не объявлена, то будет ошибка. А вот typeof boo == "undefined" сработает.

Аналогично boo === undefined срабатывает и || для неопределённого свойства или аргумента функции.

А это значит, что старый код можно улучшить ещё:

$.extend({
 getUrlVars : function(){
  var vars = {};
  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
  var i = hashes.length;
  while(i--) {
   var hash = hashes[i].split('=');
   vars[hash[0]] = hash[1];
    }
  return vars;
 },
 urlVars : null,
 getUrlVar : function(key) {
  if(!key) return null;
  if(!this.urlVars) this.urlVars = this.urlVars();
  return (this.urlVars[key] !== undefined) ? this.urlVars[key] : null;
 },
 toUrlVar : function(url, params) {
  var url_val = url || window.location.href.slice(0, window.location.href.indexOf('?'));
  var dict_params = params || this.urlVars;
  if(dict_params === undefined || !dict_params)
   return url_val;
  var params_str = "";
  for(var param_key in dict_params) {
   var param = param_key + "=" + dict_params[param_key];
   params_str += (!params_str) ? param : ("&" + param);
  }
  return params_str ? (url_val + "?" + params_str) : url_val;
 }
});

понедельник, 24 ноября 2014 г.

Удивительные факты о наследовании

Говорят, с тех пор, как в Rust и Go убрали наследование, всех сторонников объектно-ориентированной парадигмы ждёт ад и погибель. Даже вроде бы адекватные блоггеры пишут об этом и советуют забыть про ООП. Код, который приводится в качестве примера, настолько прекрасен, что я не могу его не привести:

trait Animal {
  def word: String
  def talk() { println(this.word) }
}
class Cat extends Animal { def word = "Meow!" }

class Dog extends Animal { def word = "Woof!" }

class JustACat { def meow = "Meow!" }

class HappyCat extends JustACat with Animal {
  def word = meow + " :)"
}

class SadCat extends JustACat with Animal {
  def word = meow + " :("
}
val dog = new Dog()
dog.talk

"Вот по большому счету и все, что нужно знать об АТД и классах типов" сообщает нам автор. "Забудьте об ООП! Используйте АТД и тайпклассы!".

Не имею ничего против trait-ов и языка Scala, но такой пример реализации ООП порадует разве что борцов за права домашних животных. Абсолютно непонятно, какое отношение к реальным программам имеют все эти котики и собачки и как собрать из этих грузок и перегрузок что-то работающее. Вспоминать Майерса или Буча тут не стоит - куда уместней общеизвестная песенка:

Я жму на велике любимом,
Он зовется "Украина"
Но седло от унитаза,
А педаль от пианино.
Все потырили друзья,
В двух местах сломали раму,
Ну и пусть себе смеются,
Металлисты-наркоманы!

Раз уж пошла такая путаница, надо разобраться, какое бывает ООП. Обычно под ним понимают что-то в духе C++/C#/Java - модификаторы public/private/protected, виртуальные функции, наследование, и проч., проч., проч.

Но есть языки наподобие Python, Ruby или PHP - где приватных полей нет вообще, а приватность функций зависит от доброй воли пользователя библиотеки, а типы можно сравнивать через duck typing. При этом наследование в них очень разное: в PHP оно аналогично Java (можно наследовать только от одного класса), Python разрешает множественное наследование, а в Ruby разрешает новомодные подмешивания (впрочем, большинство пользователей про них не в курсе).

Есть, наконец, JavaScript, где наследование через прототип настолько загадочно, что некоторые даже пишут свои обёртки, чтобы заменить его на что-то более привычное. И многие из этих обёрток реализуют и множественное тоже.

Ну и на закуску - есть известные реализации псевдо-ООП на C (вроде тех, что встроены в GTK и WinAPI), есть языки-надстройки вроде Lua, и громадную, ещё с начала 1990-х историю ORM для записи унаследованных объектов в реляционные базы данных.

Как легко заметить, главное в ООП - наследование, а наличие приватных полей и виртуальных функций - дело десятая. Куча народу пишет на JavaScript и не в курсе про его систему наследования, или на Python, а наследуют "как привыкли", с интерфейсами и основным классом.

О чём и было сказано уже в другом блоге, где дискуссия продолжалась: Ситуация усугубляется еще и тем, что из широкоизвестных ОО языков чисто ОО языками являются всего два -- Java и Eiffel.

вторник, 11 ноября 2014 г.

JavaScript: Receiving GET params of url - 2

Спустя два года увидел старый код, ужаснулся и всё переписал. Получилось короче и на порядок надёжней.
$.extend({
 UrlVars : null,
 getUrlVars : function(){
  if(this.UrlVars) return this.UrlVars;
  this.UrlVars = {};
  var index_separator = window.location.href.indexOf('?') + 1;
  if (index_separator) {
  var hashes = window.location.href.slice(index_separator).split('&');
  var i = hashes.length;
  while(i--){
   var hash = decodeURIComponent(hashes[i]).split('=');
   this.UrlVars[hash[0]] = hash[1];
  }
 }
 return this.UrlVars;
 },
 getUrlVar : function(key) {
 if(!key) return null;
 var vars = this.getUrlVars();
 return (typeof(vars[key]) != "undefined") ? vars[key] : "";
 }
});

понедельник, 30 июня 2014 г.

Судьба Yume Hikki

Если что - этот проект, принёсший немало веселья, закрыт уже два года как.

Окончательно добило его обнаружение фундаментальной ошибки (бывшей и в презентации, которая его вдохновила) - не надо делать JavaScript-игры на div-ах, это медленно. В JavaScript есть Canvas, на ней и рисуйте.

четверг, 18 июля 2013 г.

воскресенье, 16 сентября 2012 г.

showModalDialog’s returnValue is undefined in Chrome

С мест сообщают – в Chrome у showModalDialog returnValue – undefined. Баг известен с 2010 года и пока (16 сентября 2012) не исправлен.

Фиксить так:

В окне, которое вызывает модальное:

window.returnValue = undefined;
var result = window.showModalDialog("modalwindow.aspx", window, "dialogHeight:650px; dialogWidth:900px;");
if (result == undefined)
   result = window.returnValue;
if (result != null && result != "undefined")
  // Do something with the return value
  // defined in "result"

В модальном окне:

if (window.opener) {
    window.opener.returnValue = "your return value";
}
window.returnValue = "your return value";
self.close();

IE isn’t focusing anchor link

В IE обнаружен загадочный баг.

Если ASP.Net страница:

  • делает (например, по нажатию на страницу) redirect на другую через anchor (т.е. otherPage.aspx#anchor)
  • в IIS настроен ISAPI_Rewrite (локально повторить не удалось)
  • браузер – IE (повторяется в т.ч. в 9-ом)

То может случится так, что anchor “отбросится” и страниця загрузится как otherPage.aspx.

Выловить и перенастроить практически невозможно.

Единственный выход – вместо redirect вставлять в literal на странице “<script language=’javascript’>location.href = ‘otherPage.aspx#anchor’;</script>”. Можно дополнительно поставить проверку – делать такой redirect только если браузер ie. Название браузера искать в Request.Browser.Type.

О document.ready заботаться не стоит – redirect он и есть redirect.

суббота, 25 августа 2012 г.

Click() doesn’t work in Chrome and Safari

Иногда нужно сделать, чтобы файл загружался не через форму по умолчанию (которая отличается у разных браузеров), а по нажатию на кнопку. Форму прячут, вместо неё ставят кнопку и вызывают по щелчку для неё click() для спрятанной формы.

Как правило, это работает. Но в браузерах на движке WebKit (например, Chrome и Safari) может и не сработать. В частности, Safari игнорирует click() по скрытым объектам.

Поэтому надо скрывать “народным” способом, чтобы не поломать вёрстку:

Вместо:

display: none;

Поставить в CSS:

width: 0px;
height: 0px;
position: absolute;

среда, 20 июня 2012 г.

JavaScript: keydown event in Opera

Я уже писал про сайт-бродилку. Легко заметить, что в Opera он работает неправильно - если зажать стрелку, то главный герой сместится только на один шаг.

Почему так происходит? Можно ли это исправить?

Эксперименты показали, что если зажать кнопку со стрелкой, то Opera отловить как keydown только сам момент нажатия. Пока не отпустишь кнопку - события в JavaScript происходить не будет, оно будет перенаправлятсья на Scroll Bar.

Так что из Opera можно бродить только шаг за шагом. И отладчик в ней вызывается не как у людей.

пятница, 15 июня 2012 г.

jQuery: "name.replace is not a function" error

It's a very widely known error, since jQuery 1.0 probably. I'll describe he solution en English, because there aren't any English manual for it too.

If you implement the OOP inheritance in JavaScript using this very famous code:

Object.prototype.Inherits = function(parent)
{
 if(arguments.length > 1)
  parent.apply(this, Array.prototype.slice.call(arguments,1));
 else
  parent.call(this);
}

Function.prototype.Inherits = function(parent)
{
 this.prototype = new parent();
 this.prototype.constructor = this;
}

fadeIn() and fadeOut() will cause this error :-(.

Anyway, this version of inheritance isn't so good at all, because it breaks JavaScript foreach-like for too, adding 1 more element "Inherits" to every array.

But what if you have to use it? Is there any way to fix?

Firstly, update this implementation to make it safe:

Object.prototype.Inherits = function(parent)
{
 if(!parent || typeof(parent.call) != "function")
  return;
 if(arguments.length > 1)
  parent.apply(this, Array.prototype.slice.call(arguments,1));
 else
  parent.call(this);
}

Function.prototype.Inherits = function(parent)
{
 this.prototype = new parent();
 this.prototype.constructor = this;
}

Then update jQuery.js (is you have a min version, replace it with full one). Find "getComputedStyle = function( elem, name ) {" and add after first 2 lines:

getComputedStyle = function( elem, name ) {
 var ret, defaultView, computedStyle, width,
  style = elem.style;
 //Add this:
 if(typeof(name) != "string")
  return name;
 //-----

And it will work fine :-)

среда, 13 июня 2012 г.

JavaScript: Receiving GET params of url

Как прочитать в JavaScript параметры, которые идут в URL сразу после ? и имеют вид key=value?

Внимательно вчитаться в образец и сделать ещё удобней:

$.extend({
 getUrlVars: function(){
  var vars = [], hash;
  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
  var hashesLength = hashes.length;
  var i = 0
  while(i < hashesLength)
  {
   hash = hashes[i].split('=');
   vars.push(hash[0]);
   vars[hash[0]] = hash[1];
   i++;
  }
  return vars;
 },
 UrlVars : null,
 getUrlVar : function(key) {
  if(!key)
   return null;
  if(!this.UrlVars)
   this.UrlVars = this.getUrlVars();
  if(typeof(this.UrlVars[key]) == "undefined")
   return null;
  else
   return this.UrlVars[key];
 }
});

И теперь в любом месте вызываем $.getUrlVar('key') и получаем этот параметр. Если параметра не было - вернёт null.