Блог Сергея Байдачного

Мой блог о технологиях

Archive for the ‘Internet Explorer 10’ Category

Толерантность в WordPress

leave a comment »

Только что сломался WordPress (или я довел свою машину до такого состояния). Выдает сообщение о том, что мой браузер устарел (для любых браузеров). Но радует то, что WordPress максимально лоялен к пользователю и предлагает обновить уже установленный (используемый в данный момент) на машине браузер, а не предлагает мне какое-то Г… или что-то в этом роде.

Вот:

clip_image002

или

clip_image004

И т. д.

Реклама

Written by Sergiy Baydachnyy

30.08.2011 at 22:11

Опубликовано в Internet Explorer 10, Internet Explorer 9

Tagged with

Зарисовки по JavaScript для .NET разработчиков: Конструкторы и наследование

2 комментария

В этой статье мне хотелось бы освятить различные варианты наследования в JavaScript. Но прежде чем сделать это, давайте рассмотрим некоторые особенности, которые доступны в функциях-конструкторах, чтобы закрыть вопросы, связанные с созданием объектов.

Первое, на чем мне хотелось бы остановиться, это возвращаемое значение функции-конструктора. В языке С# и других, конструкторы не имеют возвращаемого значения и, создавая объект некоторого типа, Вы всегда получаете желаемое. В JavaScript функции-конструкторы, напротив, возвращают значение. В обычном случае это ссылка this, ссылающаяся на созданный объект. Последняя генерируется в начале работы конструктора и возвращается неявно (хотя можно вернуть и явно), но, если Вы решили изменить тип возвращаемого объекта, то это легко сделать, создав внутри что-то другое и вернуть объект, используя оператор return. Вот небольшой пример:

 

   1:  function Employee() {
   2:  return new Person();
   3:  }
   4:   
   5:  function Person() {
   6:  this.firstName = "Sergiy";
   7:  this.lastName = "Baydachnyy";
   8:  };
   9:   
  10:  var obj = new Employee();
  11:   
  12:  alert(obj.firstName);

 

Используя эту возможность, можно реализовать обработку ошибки, которая возникнет, если программист вызовет функцию-конструктор как обычную функцию (то есть без оператора new):

 

   1:  function Person() {
   2:  if (!(this instanceof Person)) {
   3:     return new Person();
   4:  }
   5:  this.firstName = "Sergiy";
   6:  this.lastName = "Baydachnyy";
   7:  }
   8:   
   9:  var obj = Person();
  10:   
  11:  alert(obj.firstName);

 

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

Вызов конструктора базового класса.

Мой любимый способ наследования, это вызов конструктора «базового класса» в конструкторе «производного класса». Иными словами, создавай объект с помощью функции-конструктора, Вы инициируете вызов другой (других) функции-конструктора, передавая текущий контекст. При этом инициализация последней выполняется без использования оператора new (так как он создает новый контекст), а прямым вызовом функции. В этом случае, создаваемый объект получает все данные и методы, объявленные в вызываемой функции-конструкторе. Посмотрим на примере:

 

   1:  function Person(fName, lName) {
   2:  this.firstName = fName;
   3:  this.lastName = lName;
   4:  this.Name = (function () { return this.firstName + " " + this.lastName });
   5:  }
   6:   
   7:  function Developer(fName, lName, lang) {
   8:  Person.call(this,fName, lName);
   9:  this.language = lang;
  10:  }
  11:   
  12:  var d = new Developer("Sergiy", "Baydachnyy", "C#");
  13:   
  14:  alert(d.Name());

 

Из кода видно, что мы используем метод call для установки контекста функции-конструктору. Аналогично можно было бы использовать и метод apply. Данный подход мне нравится тем, что позволяет получить все свойства и методы наследуемого объекта, с возможностью их вызова внутри самого конструктора.

Между тем у этого подхода есть несколько недостатков:

· Методы, которые объявляются в прототипах, никоим образом не попадают в производный объект. Иными словами в производный объект попадает все, что объявлено с помощью this;

· Определить связь с наследуемым объектом нет никакой возможности. Иными словами instanceof полностью работать не будет;

· Поскольку методы в JavaScript также являются объектами и занимают какую-то память, то эффективнее использовать ссылку на метод вместо его дублирования.

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

Использование прототипа.

Метод, основанный на использовании прототипов, состоит в том, что в свойство prototype производного объекта устанавливается ссылка на базовый объект (созданный с помощью new). В этом случае производный объект получает доступ ко всем полям базового объекта. При этом цепочка наследований может быть сколь угодно длинной.

 

   1:  function Person(fName, lName) {
   2:  this.firstName = fName;
   3:  this.lastName = lName;
   4:  this.Name = (function () { return this.firstName + " " + this.lastName });
   5:  }
   6:   
   7:  function Developer(lang, fName, lName) {
   8:  this.language = lang;
   9:  this.firstName = fName;
  10:  this.lastName = lName;
  11:  this.constructor = Developer;
  12:  }
  13:   
  14:  Developer.prototype = new Person();
  15:  var d = new Developer("C#", "Sergiy", "Baydachnyy");
  16:   
  17:  alert(d.Name());

 

Обратите внимание, что этот код не только устанавливает свойство prototype, но и изменяет свойство constructor, которое меняется по ходу установки prototype.

Этот подход также обладает рядом недостатков:

· Установку прототипа нужно выполнять вне функции-конструктора. Это означает, что мы не сможем воспользоваться методами базового объекта внутри конструктора производного;

· Поскольку при инициализации прототипа мы задаем шаблон для всех будущих объектов, нет смысла использовать параметры в конструкторе базового объекта. Данные нужно дублировать, в противном случае они будут общими для всех объектов. Мы можем даже написать код, который удаляет лишние поля данных из прототипа;

· Изменение прототипа скажется на всех объектах, включая производные;

· Код по конструированию объекта разбит на отдельные части в разных областях приложения, что меня, как ООП разработчика очень пугает;

Комбинация двух методов.

Часто, чтобы перенести данные и методы базового объекта в производный, сохранив при этом цепочку прототипов, прибегают к комбинации обоих методов. То есть, в конструкторе производного объекта вызывают функцию-конструктор базового (в текущем контексте), а далее устанавливают прототипы. Подобный подход нас практически избавляет от недостатков первого метода, но недостатки второго метода реализации наследования, остаются.

Наследование в ECMA Script 5

Существует еще один механизм наследования, о котором я не говорил, это наследование через прототип. В этом случае мы прототипу одного объекта присваиваем прототип другого объекта (иногда через создание промежуточной функции с пустым прототипом). А затем расширяем объект по своему усмотрению.

Мне этот метод не особо нравится, так как он также не позволяет красиво группировать код. В тоже время он существует и ECMA Script 5 определяет специальный метод у Object, который создает объект наследник через прототип:

 

   1:  function Person(fName, lName) {
   2:  this.firstName = fName;
   3:  this.lastName = lName;
   4:  Person.prototype.Name = (function () { return this.firstName + " " + this.lastName });
   5:  }
   6:   
   7:  var s = Object.create(new Person("Sergiy", "Baydachnyy"));
   8:   
   9:  //теперь можно расширять созданный объект

 

В завершении отмечу, что «тупое» копирование ссылок на методы базового объекта также является вариантом наследования. В зависимости от задачи, Вы легко можете комбинировать различные методы.

Вот, например, интересный код, который мне пришел в голову:

 

   1:  function Person(fName, lName) {
   2:  this.firstName = fName;
   3:  this.lastName = lName;
   4:  Person.prototype.Name = (function () { return this.firstName + " " + this.lastName });
   5:  }
   6:   
   7:  function Developer(lang, fName, lName) {
   8:   
   9:  function IDeveloper() {
  10:  }
  11:   
  12:  IDeveloper.prototype = new Person(fName,lName);
  13:  var that = new IDeveloper();
  14:  that.language = lang;
  15:  that.constructor = Developer;
  16:  return that;
  17:  }
  18:   
  19:  var d = new Developer("C#", "Sergiy", "Baydachnyy");

 

Этот код характерен тем, что не позволяет расширять прототипы за пределами конструктора, так как каждый раз создается новый объект типа IDeveloper, но с точки зрения ООП выглядит интересно. Наверняка его можно и улучшить.

Written by Sergiy Baydachnyy

29.08.2011 at 18:24

Опубликовано в Internet Explorer 10, Internet Explorer 9, JavaScript

Tagged with

Зарисовки по JavaScript для .NET разработчиков: Любовь к JSON

with one comment

Не знаю как Вам, но мне приходилось писать множество веб-служб для внутреннего использования другими частями приложения. И всегда, когда приходилось принимать решение о том, в каком виде возвращать данные, я выбирал XML. Что может быть лучше супер-универсального протокола SOAP, получившего значительное расширения в WCF? И что может быть проще сериализации и десериализации на основе XML в .NET Framework?

Вот только нужна ли универсальность SOAP и избыточность XML при реализации внутренних служб. Ведь формат передаваемых данных четко специфицирован. Кроме того, что делать разработчику, который программирует клиент, используя JavaScript. Конечно, можно предложить ему набор оберток (сгенерированных внешней утилитой), выполняющих черновую работу или заставить писать клиент только на ASP.NET и использовать ScriptManager. Но есть и другой вариант, состоящий в поддержке Вашими службами протокола JSON.

Ранее, читая о поддержке JSON в ASP.NET или Bing службах, я не придавал этому особого значения, но когда я начал писать приложения на JavaScript, то тут же потерял желание обрабатывать XML.

Прежде чем перейти к описанию работы с JSON, посмотрим на еще один способ создания объекта в JavaScript, это литералы. Вот пример создания небольшого объекта:

 

   1:  var obj1 = {
   2:   
   3:  firstName: "Sergey",
   4:  lastName: "Baydachnyy",
   5:   
   6:  Name: (function () {
   7:  return this.firstName + " " + this.lastName;
   8:  })
   9:   
  10:  };
  11:   
  12:  alert(obj1.Name());

 

Тут мы добавили два поля с данными и один метод. Естественно, что сейчас нас интересуют только данные, но так Вы получите более полное представление о JavaScript. Создав объект таким образом, Вы можете без труда добавлять свойства и методы к этому объекту в любом месте когда (как я писал в первой статье).

Из кода видно, что литерал позволяет создавать объект с помощью литерала в формате имя поля : значение. А вот теперь вернемся к JSON или к JavaScript Object Notation. Уже по одному названию понятно, что данные с помощью JSON передаются в аналогичном формате и практически готовы для создания объекта. «Практически» вкралось не случайно, так как данные могут содержать дополнительную мета информацию и множество лишних кавычек (в формате JSON имя также заключается в кавычки, что не обязательно для литерала).

Чтобы подготовить данные к преобразованию в объект, достаточно использовать специальный объект JSON, содержащий два метода: parse и stringify. Первый метод преобразует JSON данные в объект, а второй – наоборот:

 

   1:  var jsonData = 
   2:     '{"firstName":"Sergiy","lastName":"Baydachnyy"}';
   3:   
   4:  var obj1 = JSON.parse(jsonData);
   5:   
   6:  alert(obj1.firstName);

 

Таким образом, обрабатывать JSON данные в JavaScript достаточно просто. Что касается объекта JSON, то сегодня он поддерживается всеми браузерами, включая Internet Explorer 9, поэтому различные альтернативы уже можно и не использовать (в сети есть масса примеров с eval и др. – не все они сейчас актуальны).

Written by Sergiy Baydachnyy

26.08.2011 at 16:57

Зарисовки по JavaScript для .NET разработчиков: Больше строгости

leave a comment »

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

Как я писал ранее, JavaScript позволяет объявить переменную с помощью ключевого слова var и область видимости переменной задается функцией или глобальным объектом. Но помимо переменных в JavaScript присутствуют свойства объектов. Чтобы объявить свойство, достаточно записать имя объекта (или использовать par1в функции-конструкторе), а затем, через точку, имя свойства, которому присвоить некоторое значение:

 

   1:  p.i=3;

 

Свойства можно объявить и при создании объекта с помощью литерала, а также расширяя прототип объекта. В конечном итоге это сейчас не важно. Сконцентрируемся на том, можно ли добавить свойство к глобальному объекту? Можно, и для этого можно использовать слово this в контексте глобального объекта, объект window или же просто записать имя свойства и присвоить ему значение:

 

   1:  par1 = 5;
   2:   
   3:  alert(window.par1);

 

Код выше замечательно работает в любом месте приложения, объявляя свойство глобального объекта par1, а затем печатая его содержимое на экран.

А теперь представим себе код, в котором мы объявляем переменную с некоторым именем, а ниже, меняем значение этой переменной, но допускаем опечатку в имени (например, я все время вместо window пишу windows):

 

(function test() {

var val1 = 10;

. . . . .

vall1 = 11;

})();

 

В данном коде не произойдет никакой ошибки. По мнению JavaScript мы определяем переменную val1, а затем определяем свойство глобального объекта vall1. Как долго Вы будете искать подобные ошибки, и нужна ли Вам такая не строгость при объявлении переменных и свойств? Возможно, стоило бы исключить подобные неоднозначности из языка. Так вот, при разработке версии ECMA Script 5 об этом подумали и решили ввести специальную возможность, исключающую неоднозначности и старые возможности языка из Вашего кода – это специальный режим strict. В будущем планируется, что подобный режим будет работать по умолчанию, но поскольку реализаций ECMA Script 5 сейчас практически нигде нет, а старых библиотек громадное количество, Вы сами можете решать, где включать strict режим, а где нет.

Процедура следующая: при разработке собственного кода, в области видимости Ваших функций, вы указываете текстовую строку use strict”;, которая включает strict режим в тех браузерах, где он поддерживается. В остальных браузерах JavaScript сталкивается со строковым литералом, который не приносит особого вреда. На следующем этапе Вы тестируете Ваше приложение в браузерах, поддерживающих strict, и избавляетесь от «плохого» кода (поскольку получаете ошибки во время выполнения там, где раньше все хорошо работало в условиях неоднозначности). Таким образом, если мы изменим код нашей функции, используя strict, то должны получить сообщение об ошибке:

 

   1:  (function test() {
   2:   
   3:  "use strict";
   4:   
   5:  var val1 = 10;
   6:   
   7:  . . . . .
   8:   
   9:  vall1 = 11;
  10:   
  11:  })();

 

Осталось найти браузер, который уже поддерживает какие-то возможности ECMA Script 5. Поскольку во время написания этого поста я ехал в поезде, то пришлось пробовать те браузеры, которые у меня стояли на машине: Internet Explorer 9, Opera 11.11, Internet Explorer 10 Platform Preview. (Opera у меня стоит только для демонстрации своей несостоятельности). Конечно, я бросился проверять данный код в Opera. И был удивлен тем, что там он замечательно работает и не выдает ошибку. Аналогичная реакция была и в IE 9. Но вот Internet Explorer 10 меня порадовал:

 

image

 

Вот она ошибочка. И время на ее поиски совсем не потрачено.

И стало мне хорошо и приятно за наш Internet Explorer 10.

Но вернемся к JavaScript. Существует еще один механизм определения «плохого» кода. Это специальная утилита, которую можно найти по адресу http://jslint.com/. Если наш код скопировать в окно на этом сайте, то мы получим аналогичную ошибку. Именно поэтому, тестирование кода в режиме strict, а также использование утилиты JSLint, позволит Вам писать хороший код без ошибок.

Конечно, копировать Ваш код из окна Visual Studio дело неблагодарное (учитывая поток изменений), поэтому рекомендую всем скачать соответствующий плагин для Visual Studio 2010 с сайта http://jslint4vs2010.codeplex.com/. И будет Вам счастье:

 

image

Written by Sergiy Baydachnyy

26.08.2011 at 14:05

Опубликовано в Internet Explorer 10, JavaScript

Tagged with ,