Ðогда Ð¼Ñ ÑабоÑаем Ñ Ð²Ð½ÐµÑними даннÑми, Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ ÑамÑе ÑазнÑе оÑибки.
ÐÑли пÑиложение Ñложное, Ñо оÑибки еÑÑеÑÑвеннÑм обÑазом ÑкладÑваÑÑÑÑ Ð² иеÑаÑÑ
иÑ, ÑазобÑаÑÑÑÑ Ð² коÑоÑой Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ instanceof.
Свой обÑÐµÐºÑ Ð¾Ñибки
ÐÐ»Ñ Ð¿ÑимеÑа Ñоздадим ÑÑнкÑÐ¸Ñ readUser(json), коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ ÑазбиÑаÑÑ JSON Ñ Ð´Ð°Ð½Ð½Ñми поÑеÑиÑелÑ. ÐÑ ÐµÐ³Ð¾ полÑÑаем Ñ ÑеÑвеÑа â можеÑ, наÑего, а Ð¼Ð¾Ð¶ÐµÑ â ÑÑжого, в обÑем â желаÑелÑно пÑовеÑиÑÑ Ð½Ð° оÑибки. РможеÑ, ÑÑо даже и не JSON, а какие-Ñо дÑÑгие даннÑе â не важно, Ð´Ð»Ñ Ð½Ð°Ð³Ð»ÑдноÑÑи поÑабоÑаем Ñ JSON.
ÐÑÐ¸Ð¼ÐµÑ json на вÑ
оде в ÑÑнкÑиÑ: { "name": "ÐаÑÑ", "age": 30 }.
РпÑоÑеÑÑе ÑабоÑÑ readUser Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ ÑазлиÑнÑе оÑибки. Ðдна â оÑевидно, SyntaxError â еÑли пеÑедан некоÑÑекÑнÑй JSON.
Ðо могÑÑ Ð±ÑÑÑ Ð¸ дÑÑгие, напÑÐ¸Ð¼ÐµÑ PropertyError â ÑÑа оÑибка бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÑÑ, еÑли в пÑоÑиÑанном обÑекÑе Ð½ÐµÑ ÑвойÑÑва name или age.
РеализÑем клаÑÑ PropertyError:
function PropertyError(property) {
Error.call(this, property) ;
this.name = "PropertyError";
this.property = property;
this.message = "ÐÑибка в ÑвойÑÑве " + property;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, PropertyError);
} else {
this.stack = (new Error()).stack;
}
}
PropertyError.prototype = Object.create(Error.prototype);
Ð ÑÑом коде Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе видеÑÑ ÑÑд важнÑÑ Ð´ÐµÑалей, важнÑÑ Ð¸Ð¼ÐµÐ½Ð½Ð¾ Ð´Ð»Ñ Ð¾Ñибок:
nameâ Ð¸Ð¼Ñ Ð¾Ñибки.-
Ðолжно ÑовпадаÑÑ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ ÑÑнкÑии.
messageâ ÑообÑение об оÑибке.-
ÐеÑмоÑÑÑ Ð½Ð° Ñо, ÑÑо
PropertyErrorнаÑледÑÐµÑ Ð¾ÑError(поÑледнÑÑ ÑÑÑока), конÑÑÑÑкÑÐ¾Ñ Ñ Ð½ÐµÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ дÑÑгой. Ðн пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð½Ðµ ÑообÑение об оÑибке, а название ÑвойÑÑваproperty, Ð½Ñ Ð° ÑообÑение генеÑиÑÑеÑÑÑ Ð¸Ð· него.Ð ÑезÑлÑÑаÑе в обÑекÑе оÑибки еÑÑÑ ÐºÐ°Ðº ÑÑандаÑÑное ÑвойÑÑво
message, Ñак и более ÑоÑноеproperty.ÐÑо ÑаÑÑÐ°Ñ Ð¿ÑакÑика â добавлÑÑÑ Ð² обÑÐµÐºÑ Ð¾Ñибки ÑвойÑÑва, коÑоÑÑÑ Ð½ÐµÑ Ð² базовÑÑ Ð¾Ð±ÑекÑаÑ
Error, более подÑобно опиÑÑваÑÑие ÑиÑÑаÑÐ¸Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ клаÑÑа оÑибок. stackâ ÑÑек вÑзовов, коÑоÑÑе в иÑоге пÑивели к оÑибке.-
У вÑÑÑоеннÑÑ Ð¾Ð±ÑекÑов
ErrorÑÑо ÑвойÑÑво еÑÑÑ Ð°Ð²ÑомаÑиÑеÑки, Ð²Ð¾Ñ Ðº пÑимеÑÑ:function f() { alert( new Error().stack ); } f(); // вÑÐ²ÐµÐ´ÐµÑ ÑпиÑок вложеннÑÑ Ð²Ñзовов, Ñ Ð½Ð¾Ð¼ÐµÑами ÑÑÑок, где они бÑли ÑделанÑÐÑли же обÑÐµÐºÑ Ð¾Ñибки делаем мÑ, Ñо «по ÑмолÑаниÑ» Ñакого ÑвойÑÑва Ñ Ð½ÐµÐ³Ð¾ не бÑдеÑ. Ðам нÑжно как-Ñо Ñамим ÑзнаваÑÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½ÑÑ Ð²Ñзовов на ÑекÑÑий моменÑ. Ðднако Ñдобного ÑпоÑоба ÑделаÑÑ ÑÑо в JavaScript неÑ, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ð¿Ð¾ÑÑÑпаем Ñ Ð¸ÑÑо и копиÑÑем его из нового обÑекÑа
new Error, коÑоÑÑй генеÑиÑÑем ÑÑÑ Ð¶Ðµ.Ð V8 (Chrome, Opera, Node.JS) еÑÑÑ Ð½ÐµÑÑандаÑÑное ÑаÑÑиÑение Error.captureStackTrace, коÑоÑое позволÑÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ ÑÑек.
ÐÑо Ð´ÐµÐ»Ð°ÐµÑ ÑÑÑока из кода вÑÑе:
Error.captureStackTrace(this, PropertyError);Такой вÑзов запиÑÑÐ²Ð°ÐµÑ Ð² обÑекÑ
this(ÑекÑÑий обÑÐµÐºÑ Ð¾Ñибки) ÑÑек вÑзовов, Ð½Ñ Ð° вÑоÑой аÑгÑÐ¼ÐµÐ½Ñ â вообÑе не обÑзаÑелен, но еÑли еÑÑÑ, Ñо говоÑиÑ, ÑÑо пÑи генеÑаÑии ÑÑека нÑжно на ÑÑой ÑÑнкÑии оÑÑановиÑÑÑÑ. Ð ÑезÑлÑÑаÑе в ÑÑеке бÑÐ´ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑепоÑке вложеннÑÑ Ð²Ñзовов вплоÑÑ Ð´Ð¾ вÑзоваPropertyError.То еÑÑÑ, бÑÐ´ÐµÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð²Ñзовов до генеÑаÑии оÑибки, но не вклÑÑÐ°Ñ ÐºÐ¾Ð´ Ñамого конÑÑÑÑкÑоÑа оÑибки, коÑоÑÑй, как пÑавило, не инÑеÑеÑен. Такое поведение макÑималÑно ÑооÑвеÑÑÑвÑÐµÑ Ð²ÑÑÑоеннÑм оÑибкам JavaScript.
ÐбÑÑно, когда Ð¼Ñ Ð½Ð°ÑледÑем, Ñо вÑзÑваем конÑÑÑÑкÑÐ¾Ñ ÑодиÑелÑ. Рданном ÑлÑÑае вÑзов вÑглÑÐ´Ð¸Ñ ÐºÐ°Ðº Error.call(this, message).
СÑÑого говоÑÑ, ÑÑÐ¾Ñ Ð²Ñзов здеÑÑ Ð½Ðµ обÑзаÑелен. ÐÑÑÑоеннÑй конÑÑÑÑкÑÐ¾Ñ Error ниÑего полезного не делаеÑ, даже ÑвойÑÑво this.message (не говоÑÑ Ñже о name и stack) не назнаÑаеÑ. ÐдинÑÑвеннÑй возможнÑй ÑмÑÑл его вÑзова â он ÑÑÐ°Ð²Ð¸Ñ ÑпеÑиалÑное внÑÑÑеннее ÑвойÑÑво [[ErrorData]], коÑоÑое вÑводиÑÑÑ Ð² toString и позволÑÐµÑ ÑвидеÑÑ, ÑÑо ÑÑо оÑибка. ÐоÑÑÐ¾Ð¼Ñ Ð¿Ð¾ ÑÑандаÑÑÑ Ð²ÑзÑваÑÑ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¾Ñ Error пÑи наÑледовании в ÑакиÑ
ÑлÑÑаÑÑ
Ñекомендовано.
instanceof + tryâ¦catch = â¡
ÐавайÑе ÑепеÑÑ Ð¸ÑполÑзÑем Ð½Ð°Ñ Ð½Ð¾Ð²Ñй клаÑÑ Ð´Ð»Ñ readUser:
// ÐбÑÑвление
function PropertyError(property) {
this.name = "PropertyError";
this.property = property;
this.message = "ÐÑибка в ÑвойÑÑве " + property;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, PropertyError);
} else {
this.stack = (new Error()).stack;
}
}
PropertyError.prototype = Object.create(Error.prototype);
// ÐенеÑаÑÐ¸Ñ Ð¾Ñибки
function readUser(data) {
var user = JSON.parse(data);
if (!user.age) {
throw new PropertyError("age");
}
if (!user.name) {
throw new PropertyError("name");
}
return user;
}
// ÐапÑÑк и try..catch
try {
var user = readUser('{ "age": 25 }');
} catch (err) {
if (err instanceof PropertyError) {
if (err.property == 'name') {
// еÑли в данном меÑÑе кода Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ Ð°Ð½Ð¾Ð½Ð¸Ð¼Ñ, Ñо вÑÑ Ð½Ð¾ÑмалÑно
alert( "ÐдÑавÑÑвÑйÑе, Ðноним!" );
} else {
alert( err.message ); // ÐÑибка в ÑвойÑÑве ...
}
} else if (err instanceof SyntaxError) {
alert( "ÐÑибка в ÑинÑакÑиÑе даннÑÑ
: " + err.message );
} else {
throw err; // неизвеÑÑÐ½Ð°Ñ Ð¾Ñибка, не Ð·Ð½Ð°Ñ ÑÑо Ñ Ð½ÐµÐ¹ делаÑÑ
}
}
ÐÑÑ ÑабоÑÐ°ÐµÑ â и наÑа оÑибка PropertyError и вÑÑÑÐ¾ÐµÐ½Ð½Ð°Ñ SyntaxError коÑÑекÑно генеÑиÑÑÑÑÑÑ, пеÑеÑ
ваÑÑваÑÑÑÑ, обÑабаÑÑваÑÑÑÑ.
ÐбÑаÑим внимание на пÑовеÑÐºÑ Ñипа оÑибки в try..catch. ÐпеÑаÑÐ¾Ñ instanceof пÑовеÑÑÐµÑ ÐºÐ»Ð°ÑÑ Ñ ÑÑÑÑом наÑледованиÑ. ÐÑо знаÑиÑ, ÑÑо еÑли Ð¼Ñ Ð² далÑнейÑем ÑеÑим ÑоздаÑÑ Ð½Ð¾Ð²Ñй Ñип оÑибки, наÑледÑÑÑий Ð¾Ñ PropertyError, Ñо пÑовеÑка err instanceof PropertyError Ð´Ð»Ñ ÐºÐ»Ð°ÑÑа-наÑледника Ñоже бÑÐ´ÐµÑ ÑабоÑаÑÑ. Ðод полÑÑилÑÑ ÑаÑÑиÑÑемÑм, ÑÑо оÑÐµÐ½Ñ Ð²Ð°Ð¶Ð½Ð¾.
ÐалÑнейÑее наÑледование
PropertyError â ÑÑо пÑоÑÑо обÑего вида оÑибка в ÑвойÑÑве. Создадим оÑÐ¸Ð±ÐºÑ PropertyRequiredError, коÑоÑÐ°Ñ Ð¾Ð·Ð½Ð°ÑаеÑ, ÑÑо ÑвойÑÑва неÑ.
ÐÑо подвид PropertyError, Ñак ÑÑо ÑнаÑледÑем Ð¾Ñ Ð½ÐµÑ. ÐбÑий вид конÑÑÑÑкÑоÑа-наÑледника â ÑÑандаÑÑнÑй:
function PropertyRequiredError(property) {
// вÑзÑваем конÑÑÑÑкÑÐ¾Ñ ÑодиÑÐµÐ»Ñ Ð¸ пеÑедаÑм ÑекÑÑие аÑгÑменÑÑ
PropertyError.apply(this, arguments);
...
}
ÐоÑÑаÑоÑно ли в наÑледнике пÑоÑÑо вÑзваÑÑ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¾Ñ ÑодиÑелÑ? УвÑ, неÑ.
ÐÑли Ñак поÑÑÑпиÑÑ, Ñо ÑвойÑÑво this.name бÑÐ´ÐµÑ Ð½ÐµÐºÐ¾ÑÑекÑнÑм, да и Error.captureStackTrace Ñоже полÑÑÐ¸Ñ Ð½ÐµÐ¿ÑавилÑнÑÑ ÑÑнкÑÐ¸Ñ Ð²ÑоÑÑм паÑамеÑÑом.
Ðожно ли как-Ñо попÑавиÑÑ ÐºÐ¾Ð½ÑÑÑÑкÑÐ¾Ñ ÑодиÑелÑ, ÑÑÐ¾Ð±Ñ Ð¾Ñ Ð½ÐµÐ³Ð¾ бÑло пÑоÑе наÑледоваÑÑ?
ÐÐ»Ñ ÑÑого нÑжно ÑбÑаÑÑ Ð¸Ð· него ÑÐ¿Ð¾Ð¼Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¾ конкÑеÑном клаÑÑе PropertyError, ÑÑÐ¾Ð±Ñ ÑделаÑÑ ÐºÐ¾Ð´ ÑнивеÑÑалÑнÑм. ЧаÑÑиÑно â ÑÑо возможно. Ðак Ð¼Ñ Ð¿Ð¾Ð¼Ð½Ð¸Ð¼, ÑÑÑеÑÑвÑÐµÑ ÑвойÑÑво constructor, коÑоÑое еÑÑÑ Ð² prototype по ÑмолÑаниÑ, и коÑоÑое Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ намеÑенно ÑоÑ
ÑаниÑÑ Ð¿Ñи наÑледовании.
ÐÑпÑавим ÑодиÑÐµÐ»Ñ PropertyError Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ Ñдобного наÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ñ Ð½ÐµÐ³Ð¾:
function PropertyError(property) {
this.name = "PropertyError";
this.property = property;
this.message = "ÐÑибка в ÑвойÑÑве " + property;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor); // (*)
} else {
this.stack = (new Error()).stack;
}
}
PropertyError.prototype = Object.create(Error.prototype);
PropertyError.prototype.constructor = PropertyError;
Ð ÑÑÑоке (*) вмеÑÑо ÑÑÑлки на PropertyError иÑполÑзÑем constructor ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð¸Ð¼ÐµÐ½Ð½Ð¾ конÑÑÑÑкÑÐ¾Ñ Ð´Ð»Ñ ÑекÑÑего обÑекÑа. РнаÑледнике Ñам бÑÐ´ÐµÑ PropertyRequiredError, как и задÑмано.
ÐÑ ÑбÑали Ð¾Ð´Ð½Ñ Ð¶ÑÑÑкÑÑ Ð¿ÑивÑÐ·ÐºÑ Ðº PropertyError, но Ñо вÑоÑой (this.name), ÑвÑ, ÑложноÑÑи. Ðно должно ÑодеÑжаÑÑ Ð¸Ð¼Ñ Ð¾Ñибки, Ñо еÑÑÑ, Ð¸Ð¼Ñ ÐµÑ ÑÑнкÑии-конÑÑÑÑкÑоÑа. Ðго можно полÑÑиÑÑ ÑеÑез this.name = this.constructor.name, но в IE11- ÑÑо ÑабоÑаÑÑ Ð½Ðµ бÑдеÑ.
ÐÑли поддеÑживаÑÑ IE11-, Ñо ÑÑÑ Ñж пÑидÑÑÑÑ Ð² наÑледнике его запиÑÑваÑÑ Ð²ÑÑÑнÑÑ.
ÐолнÑй код Ð´Ð»Ñ Ð½Ð°Ñледника:
function PropertyRequiredError(property) {
PropertyError.apply(this, arguments);
this.name = 'PropertyRequiredError';
this.message = 'ÐÑÑÑÑÑÑвÑÐµÑ ÑвойÑÑво ' + property;
}
PropertyRequiredError.prototype = Object.create(PropertyError.prototype);
PropertyRequiredError.prototype.constructor = PropertyRequiredError;
var err = new PropertyRequiredError("age");
// пÑойдÑÑ Ð¿ÑовеÑкÑ
alert( err instanceof PropertyError ); // true
ÐдеÑÑ Ð·Ð°Ð¾Ð´Ð½Ð¾ и message в наÑледнике бÑло пеÑезапиÑано на более ÑоÑное. ÐÑли Ñ
оÑеÑÑÑ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð·Ð°Ð¿Ð¸Ñи и пеÑезапиÑи, Ñо можно оÑоÑмиÑÑ ÐµÐ³Ð¾ в виде геÑÑеÑа ÑеÑез Object.defineProperty.
ÐÑого
- ЧÑÐ¾Ð±Ñ Ð½Ð°ÑледоваÑÑ Ð¾Ñ Ð¾Ñибок
Error, нÑжно ÑамоÑÑоÑÑелÑно позабоÑиÑÑÑÑ Ð¾name,messageиstack. - ÐлагодаÑÑ ÑомÑ, ÑÑо
instanceofподдеÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð½Ð°Ñледование, Ñдобно оÑганизÑÑÑÑÑ Ð¿ÑовеÑки на нÑжнÑй Ñип. РиеÑаÑÑ Ð¸Ñ Ð¾Ñибок можно в лÑбой Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ Ð½Ð¾Ð²Ñе клаÑÑÑ, Ñ Ð¿Ð¾Ð½ÑÑнÑм кодом и пÑедÑказÑемÑм поведением.
ЧÑÐ¾Ð±Ñ ÑоздаваÑÑ Ð½Ð°Ñледники Ð¾Ñ Error бÑло пÑоÑе, можно ÑоздаÑÑ ÐºÐ»Ð°ÑÑ CustomError, запиÑаÑÑ Ð² него ÑнивеÑÑалÑнÑй код, наподобие PropertyError и далее наÑледоваÑÑ Ñже Ð¾Ñ Ð½ÐµÐ³Ð¾:
// обÑего вида "наÑа" оÑибка
function CustomError(message) {
this.name = "CustomError";
this.message = message;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error()).stack;
}
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.constructor = CustomError;
// наÑледник
function PropertyError(property) {
CustomError.call(this, "ÐÑибка в ÑвойÑÑве " + property)
this.name = "PropertyError";
this.property = property;
}
PropertyError.prototype = Object.create(CustomError.prototype);
PropertyError.prototype.constructor = PropertyError;
// и еÑÑ ÑÑовенÑ
function PropertyRequiredError(property) {
PropertyError.call(this, property);
this.name = 'PropertyRequiredError';
this.message = 'ÐÑÑÑÑÑÑвÑÐµÑ ÑвойÑÑво ' + property;
}
PropertyRequiredError.prototype = Object.create(PropertyError.prototype);
PropertyRequiredError.prototype.constructor = PropertyRequiredError;
// иÑполÑзование
var err = new PropertyRequiredError("age");
// пÑойдÑÑ Ð¿ÑовеÑкÑ
alert( err instanceof PropertyRequiredError ); // true
alert( err instanceof PropertyError ); // true
alert( err instanceof CustomError ); // true
alert( err instanceof Error ); // true
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)