Вы знаете свой JavaScript? Взгляните на следующий пример кода и выясните, какое значение отображается в последнем операторе оповещения …
// object constructor
function ObjectConstructor(a, b, c) {
this.A = a;
this.B = b;
this.C = c;
this.Total = a + b + c;
}
var obj = ObjectConstructor(1, 2, 3);
alert(obj.Total);
Руки вверх всех, кто ответил «6».
Извините, вы не правы. Ответ … ничего — или ошибка, указывающая, что ‘obj’ не определено. Так что пошло не так?
Простой ответ заключается в том, что мы забыли оператор ‘new’, поэтому экземпляр объекта никогда не создается. Заявление должно быть:
var obj = new ObjectConstructor(1, 2, 3);
Это простая ошибка. Начинающие разработчики вряд ли заметят отсутствующий оператор, потому что код выглядит практически идентично. Даже опытным кодировщикам может быть сложно отлаживать (тем более что многие считают, что JavaScript — это процедурный язык программирования … который может быть, если вы решите написать его таким образом).
Основная проблема заключается в том, что var obj = ObjectConstructor(1, 2, 3);
является совершенно допустимым оператором JavaScript, и механизм интерпретатора не выдаст ошибку. В этом контексте значение obj устанавливается равным значению, возвращенному функцией ObjectConstructor; поскольку значение не возвращается, obj остается «неопределенным» (свойство JavaScript верхнего уровня).
Это вряд ли станет серьезной проблемой, если вы разрабатываете, тестируете и отлаживаете свой собственный код. Однако может быть другое дело, если вы предоставляете библиотеку или API тысячам сторонних разработчиков. В какой-то момент кто-то где-то пропустит этот «новый» оператор, и они обвинят ваш код, а не их.
К счастью, JavaScript — гибкий язык. Мы можем исправить наш конструктор так, чтобы объект создавался правильно, даже если опущен оператор ‘new’:
// object constructor
function ObjectConstructor(a, b, c) {
if (!(this instanceof arguments.callee)) {
return new ObjectConstructor(a, b, c);
}
this.A = a;
this.B = b;
this.C = c;
this.Total = a + b + c;
}
Дополнительный оператор ‘if’ в верхней части конструктора проверяет, является ли ‘this’ экземпляром объекта, и возвращает его в случае необходимости. Код var obj = ObjectConstructor(1, 2, 3);
теперь установит obj для экземпляра объекта, и оператором alert будет выведено «6».
Вы когда-нибудь сталкивались с этой проблемой в своем коде или при использовании другой библиотеки?