ÐÑÐµÐ¼Ñ Ð¾Ñ Ð²Ñемени бÑÐ²Ð°ÐµÑ Ñдобно ÑоздаваÑÑ Ñак назÑваемÑе «полимоÑÑнÑе» ÑÑнкÑии, Ñо еÑÑÑ Ñакие, коÑоÑÑе по-ÑÐ°Ð·Ð½Ð¾Ð¼Ñ Ð¾Ð±ÑабаÑÑваÑÑ Ð°ÑгÑменÑÑ, в завиÑимоÑÑи Ð¾Ñ Ð¸Ñ Ñипа. ÐапÑимеÑ, ÑÑнкÑÐ¸Ñ Ð²Ñвода Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾-ÑÐ°Ð·Ð½Ð¾Ð¼Ñ ÑоÑмаÑиÑоваÑÑ ÑиÑла и даÑÑ.
ÐÐ»Ñ ÑеализаÑии Ñакой возможноÑÑи нÑжен ÑпоÑоб опÑеделиÑÑ Ñип пеÑеменной.
ÐпеÑаÑÐ¾Ñ typeof
ÐÑ Ñже Ð·Ð½Ð°ÐºÐ¾Ð¼Ñ Ñ Ð¿ÑоÑÑейÑим ÑпоÑобом â опеÑаÑоÑом typeof.
ÐпеÑаÑÐ¾Ñ typeof надÑжно ÑабоÑÐ°ÐµÑ Ñ Ð¿ÑимиÑивнÑми Ñипами, кÑоме null, а Ñакже Ñ ÑÑнкÑиÑми. Ðн возвÑаÑÐ°ÐµÑ Ð´Ð»Ñ Ð½Ð¸Ñ
Ñип в виде ÑÑÑоки:
alert( typeof 1 ); // 'number'
alert( typeof true ); // 'boolean'
alert( typeof "ТекÑÑ" ); // 'string'
alert( typeof undefined ); // 'undefined'
alert( typeof null ); // 'object' (оÑибка в ÑзÑке)
alert( typeof alert ); // 'function'
â¦Ðо вÑе обÑекÑÑ, вклÑÑÐ°Ñ Ð¼Ð°ÑÑÐ¸Ð²Ñ Ð¸ даÑÑ Ð´Ð»Ñ typeof â на одно лиÑо, они имеÑÑ Ð¾Ð´Ð¸Ð½ Ñип 'object':
alert( typeof {} ); // 'object'
alert( typeof [] ); // 'object'
alert( typeof new Date ); // 'object'
ÐоÑÑÐ¾Ð¼Ñ ÑазлиÑиÑÑ Ð¸Ñ
пÑи помоÑи typeof нелÑзÑ, и в ÑÑом его оÑновной недоÑÑаÑок.
СекÑеÑное ÑвойÑÑво [[Class]]
ÐÐ»Ñ Ð²ÑÑÑоеннÑÑ
обÑекÑов еÑÑÑ Ð¾Ð´Ð½Ð° «ÑекÑеÑнаÑ» возможноÑÑÑ ÑзнаÑÑ Ð¸Ñ
Ñип, коÑоÑÐ°Ñ ÑвÑзана Ñ Ð¼ÐµÑодом toString.
Ðо вÑеÑ
вÑÑÑоеннÑÑ
обÑекÑаÑ
еÑÑÑ ÑпеÑиалÑное ÑвойÑÑво [[Class]], в коÑоÑом Ñ
ÑаниÑÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ его Ñипе или конÑÑÑÑкÑоÑе.
Ðно взÑÑо в квадÑаÑнÑе Ñкобки, Ñак как ÑÑо ÑвойÑÑво â внÑÑÑеннее. Явно полÑÑиÑÑ ÐµÐ³Ð¾ нелÑзÑ, но можно пÑоÑиÑаÑÑ ÐµÐ³Ð¾ «в обÑ
од», воÑполÑзовавÑиÑÑ Ð¼ÐµÑодом toString ÑÑандаÑÑного обÑекÑа Object.
Ðго внÑÑÑеннÑÑ ÑеализаÑÐ¸Ñ Ð²ÑÐ²Ð¾Ð´Ð¸Ñ [[Class]] в неболÑÑом обÑамлении, как "[object знаÑение]".
ÐапÑимеÑ:
var toString = {}.toString;
var arr = [1, 2];
alert( toString.call(arr) ); // [object Array]
var date = new Date;
alert( toString.call(date) ); // [object Date]
var user = { name: "ÐаÑÑ" };
alert( toString.call(user) ); // [object Object]
РпеÑвой ÑÑÑоке Ð¼Ñ Ð²Ð·Ñли меÑод toString, пÑинадлежаÑий именно ÑÑандаÑÑÐ½Ð¾Ð¼Ñ Ð¾Ð±ÑекÑÑ {}. Ðам пÑиÑлоÑÑ ÑÑо ÑделаÑÑ, Ñак как Ñ Date и Array â Ñвои ÑобÑÑвеннÑе меÑÐ¾Ð´Ñ toString, коÑоÑÑе ÑабоÑаÑÑ Ð¸Ð½Ð°Ñе.
ÐаÑем Ð¼Ñ Ð²ÑзÑваем ÑÑÐ¾Ñ toString в конÑекÑÑе нÑжного обÑекÑа obj, и он возвÑаÑÐ°ÐµÑ ÐµÐ³Ð¾ внÑÑÑеннее, невидимое дÑÑгими ÑпоÑобами, ÑвойÑÑво [[Class]].
ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ [[Class]] нÑжна именно внÑÑÑеннÑÑ ÑеализаÑÐ¸Ñ toString ÑÑандаÑÑного обÑекÑа Object, дÑÑÐ³Ð°Ñ Ð½Ðµ подойдÑÑ.
Ð ÑÑаÑÑÑÑ, меÑÐ¾Ð´Ñ Ð² JavaScript â ÑÑо вÑего лиÑÑ ÑÑнкÑии-ÑвойÑÑва обÑекÑа, коÑоÑÑе можно ÑкопиÑоваÑÑ Ð² пеÑеменнÑÑ Ð¸ пÑимениÑÑ Ð½Ð° дÑÑгом обÑекÑе ÑеÑез call/apply. ЧÑо Ð¼Ñ Ð¸ делаем Ð´Ð»Ñ {}.toString.
ÐеÑод Ñакже можно иÑполÑзоваÑÑ Ñ Ð¿ÑимиÑивами:
alert( {}.toString.call(123) ); // [object Number]
alert( {}.toString.call("ÑÑÑока") ); // [object String]
{}.toString в конÑоли Ð¼Ð¾Ð¶ÐµÑ Ð²ÑдаÑÑ Ð¾ÑибкÑÐÑи ÑеÑÑиÑовании кода в конÑоли Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе обнаÑÑжиÑÑ, ÑÑо еÑли ввеÑÑи в команднÑÑ ÑÑÑÐ¾ÐºÑ {}.toString.call(...) â бÑÐ´ÐµÑ Ð¾Ñибка. С дÑÑгой ÑÑоÑонÑ, вÑзов alert( {}.toString... ) â ÑабоÑаеÑ.
ÐÑа оÑибка Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ Ð¿Ð¾ÑомÑ, ÑÑо ÑигÑÑнÑе Ñкобки { } в оÑновном поÑоке кода инÑеÑпÑеÑиÑÑÑÑÑÑ ÐºÐ°Ðº блок. ÐнÑеÑпÑеÑаÑÐ¾Ñ ÑиÑÐ°ÐµÑ {}.toString.call(...) Ñак:
{ } // пÑÑÑой блок кода
.toString.call(...) // а ÑÑо ÑÑо за ÑоÑка в наÑале? не понимаÑ, оÑибка!
ФигÑÑнÑе Ñкобки ÑÑиÑаÑÑÑÑ Ð¾Ð±ÑекÑом, ÑолÑко еÑли они наÑ
одÑÑÑÑ Ð² конÑекÑÑе вÑÑажениÑ. Ð ÑаÑÑноÑÑи, обоÑаÑивание в Ñкобки ( {}.toString... ) Ñоже ÑÑабоÑÐ°ÐµÑ Ð½Ð¾ÑмалÑно.
ÐÐ»Ñ Ð±Ð¾Ð»ÑÑего ÑдобÑÑва можно ÑделаÑÑ ÑÑнкÑÐ¸Ñ getClass, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ ÑолÑко Ñам [[Class]]:
function getClass(obj) {
return {}.toString.call(obj).slice(8, -1);
}
alert( getClass(new Date) ); // Date
alert( getClass([1, 2, 3]) ); // Array
ÐамеÑим, ÑÑо ÑвойÑÑво [[Class]] еÑÑÑ Ð¸ доÑÑÑпно Ð´Ð»Ñ ÑÑÐµÐ½Ð¸Ñ ÑказаннÑм ÑпоÑобом â Ñ Ð²ÑеÑ
вÑÑÑоеннÑÑ
обÑекÑов. Ðо его Ð½ÐµÑ Ñ Ð¾Ð±ÑекÑов, коÑоÑÑе ÑоздаÑÑ Ð½Ð°Ñи ÑÑнкÑии. ТоÑнее, оно еÑÑÑ, но Ñавно вÑегда "Object".
ÐапÑимеÑ:
function User() {}
var user = new User();
alert( {}.toString.call(user) ); // [object Object], не [object User]
ÐоÑÑÐ¾Ð¼Ñ ÑзнаÑÑ Ñип Ñаким обÑазом можно ÑолÑко Ð´Ð»Ñ Ð²ÑÑÑоеннÑÑ Ð¾Ð±ÑекÑов.
ÐеÑод Array.isArray()
ÐÐ»Ñ Ð¿ÑовеÑки Ñипа на маÑÑив еÑÑÑ ÑпеÑиалÑнÑй меÑод: Array.isArray(arr). Ðн возвÑаÑÐ°ÐµÑ true ÑолÑко еÑли arr â маÑÑив:
alert( Array.isArray([1,2,3]) ); // true
alert( Array.isArray("not array")); // false
Ðо ÑÑÐ¾Ñ Ð¼ÐµÑод â единÑÑвеннÑй в ÑвоÑм Ñоде.
ÐÑÑгиÑ
аналогиÑнÑÑ
, Ñипа Object.isObject, Date.isDate â неÑ.
ÐпеÑаÑÐ¾Ñ instanceof
ÐпеÑаÑÐ¾Ñ instanceof позволÑÐµÑ Ð¿ÑовеÑиÑÑ, Ñоздан ли обÑÐµÐºÑ Ð´Ð°Ð½Ð½Ð¾Ð¹ ÑÑнкÑией, пÑиÑÑм ÑабоÑÐ°ÐµÑ Ð´Ð»Ñ Ð»ÑбÑÑ
ÑÑнкÑий â как вÑÑÑоеннÑÑ
, Ñак и наÑиÑ
.
function User() {}
var user = new User();
alert( user instanceof User ); // true
Таким обÑазом, instanceof, в оÑлиÑие Ð¾Ñ [[Class]] и typeof Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð²ÑÑÑниÑÑ Ñип Ð´Ð»Ñ Ð½Ð¾Ð²ÑÑ
обÑекÑов, ÑозданнÑÑ
наÑими конÑÑÑÑкÑоÑами.
ÐамеÑим, ÑÑо опеÑаÑÐ¾Ñ instanceof â Ñложнее, Ñем кажеÑÑÑ. Ðн ÑÑиÑÑÐ²Ð°ÐµÑ Ð½Ð°Ñледование, коÑоÑое Ð¼Ñ Ð¿Ð¾ÐºÐ° не пÑоÑ
одили, но ÑкоÑо изÑÑим и заÑем веÑнÑмÑÑ Ðº instanceof в главе ÐÑовеÑка клаÑÑа: "instanceof".
УÑÐ¸Ð½Ð°Ñ ÑипизаÑиÑ
ÐлÑÑеÑнаÑивнÑй Ð¿Ð¾Ð´Ñ Ð¾Ð´ к ÑÐ¸Ð¿Ñ â «ÑÑÐ¸Ð½Ð°Ñ ÑипизаÑиÑ», коÑоÑÐ°Ñ Ð¾Ñнована на одной извеÑÑной поÑловиÑе: «If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)».
РпеÑеводе: «ÐÑли ÑÑо вÑглÑÐ´Ð¸Ñ ÐºÐ°Ðº ÑÑка, Ð¿Ð»Ð°Ð²Ð°ÐµÑ ÐºÐ°Ðº ÑÑка и кÑÑÐºÐ°ÐµÑ ÐºÐ°Ðº ÑÑка, Ñо, веÑоÑÑно, ÑÑо ÑÑка (ÐºÐ°ÐºÐ°Ñ ÑазниÑа, ÑÑо ÑÑо на Ñамом деле)».
СмÑÑл ÑÑиной ÑипизаÑии â в пÑовеÑке Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼ÑÑ Ð¼ÐµÑодов и ÑвойÑÑв.
ÐапÑимеÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ пÑовеÑиÑÑ, ÑÑо обÑÐµÐºÑ â маÑÑив, не вÑзÑÐ²Ð°Ñ Array.isArray, а пÑоÑÑо ÑÑоÑнив налиÑие важного Ð´Ð»Ñ Ð½Ð°Ñ Ð¼ÐµÑода, напÑÐ¸Ð¼ÐµÑ splice:
var something = [1, 2, 3];
if (something.splice) {
alert( 'ÐÑо ÑÑка! То еÑÑÑ, маÑÑив!' );
}
ÐбÑаÑиÑе внимание â в if Ð¼Ñ Ð½Ðµ вÑзÑваем меÑод something.splice(), а пÑобÑем полÑÑиÑÑ Ñамо ÑвойÑÑво something.splice. ÐÐ»Ñ Ð¼Ð°ÑÑивов оно вÑегда еÑÑÑ Ð¸ ÑвлÑеÑÑÑ ÑÑнкÑией, Ñ.е. даÑÑ Ð² логиÑеÑком конÑекÑÑе true.
ÐÑовеÑиÑÑ Ð½Ð° даÑÑ Ð¼Ð¾Ð¶Ð½Ð¾, опÑеделив налиÑие меÑода getTime:
var x = new Date();
if (x.getTime) {
alert( 'ÐаÑа!' );
alert( x.getTime() ); // ÑабоÑаем Ñ Ð´Ð°Ñой
}
С Ð²Ð¸Ð´Ñ ÑÐ°ÐºÐ°Ñ Ð¿ÑовеÑка Ñ ÑÑпка, ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ «ÑломаÑÑ», пеÑедав Ð¿Ð¾Ñ Ð¾Ð¶Ð¸Ð¹ обÑÐµÐºÑ Ñ Ñем же меÑодом.
Ðо как Ñаз в ÑÑом и еÑÑÑ ÑмÑÑл ÑÑиной ÑипизаÑии: еÑли обÑÐµÐºÑ Ð¿Ð¾Ñ Ð¾Ð¶ на даÑÑ, Ñ Ð½ÐµÐ³Ð¾ еÑÑÑ Ð¼ÐµÑÐ¾Ð´Ñ Ð´Ð°ÑÑ, Ñо бÑдем ÑабоÑаÑÑ Ñ Ð½Ð¸Ð¼ как Ñ Ð´Ð°Ñой (ÐºÐ°ÐºÐ°Ñ ÑазниÑа, ÑÑо ÑÑо на Ñамом деле).
То еÑÑÑ Ð¼Ñ Ð½Ð°Ð¼ÐµÑенно позволÑем пеÑедаÑÑ Ð² код неÑÑо менее конкÑеÑное, Ñем опÑеделÑннÑй Ñип, ÑÑÐ¾Ð±Ñ ÑделаÑÑ ÐµÐ³Ð¾ более ÑнивеÑÑалÑнÑм.
ÐÑли говоÑиÑÑ Ñловами «клаÑÑиÑеÑкого пÑогÑаммиÑованиÑ», Ñо «duck typing» â ÑÑо пÑовеÑка ÑеализаÑии обÑекÑом ÑÑебÑемого инÑеÑÑейÑа. ÐÑли ÑеализÑÐµÑ â ок, иÑполÑзÑем его. ÐÑли Ð½ÐµÑ â знаÑÐ¸Ñ ÑÑо ÑÑо-Ñо дÑÑгое.
ÐÑÐ¸Ð¼ÐµÑ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑной ÑÑнкÑии
ÐÑÐ¸Ð¼ÐµÑ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑной ÑÑнкÑии â sayHi(who), коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð³Ð¾Ð²Ð¾ÑиÑÑ Â«ÐÑивеÑ» ÑÐ²Ð¾ÐµÐ¼Ñ Ð°ÑгÑменÑÑ, пÑиÑÑм еÑли пеÑедан маÑÑив â Ñо «ÐÑивеÑ» каждомÑ:
function sayHi(who) {
if (Array.isArray(who)) {
who.forEach(sayHi);
} else {
alert( 'ÐÑивеÑ, ' + who );
}
}
// ÐÑзов Ñ Ð¿ÑимиÑивнÑм аÑгÑменÑом
sayHi("ÐаÑÑ"); // ÐÑивеÑ, ÐаÑÑ
// ÐÑзов Ñ Ð¼Ð°ÑÑивом
sayHi(["СаÑа", "ÐеÑÑ"]); // ÐÑивеÑ, СаÑа... ÐеÑÑ
// ÐÑзов Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ñми маÑÑивами - Ñоже ÑабоÑаеÑ!
sayHi(["СаÑа", "ÐеÑÑ", ["ÐаÑа", "ЮлÑ"]]); // ÐÑÐ¸Ð²ÐµÑ Ð¡Ð°Ñа..ÐеÑÑ..ÐаÑа..ЮлÑ
ÐÑовеÑÐºÑ Ð½Ð° маÑÑив в ÑÑом пÑимеÑе можно замениÑÑ Ð½Ð° «ÑÑинÑÑ» â нам Ð²ÐµÐ´Ñ Ð½Ñжен ÑолÑко меÑод forEach:
function sayHi(who) {
if (who.forEach) { // еÑли еÑÑÑ forEach
who.forEach(sayHi); // пÑедполагаем, ÑÑо он ведÑÑ ÑÐµÐ±Ñ "как надо"
} else {
alert( 'ÐÑивеÑ, ' + who );
}
}
ÐÑого
ÐÐ»Ñ Ð½Ð°Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑÑ (ÑÑо Ñдобно!) ÑÑнкÑий нам нÑжна пÑовеÑка Ñипов.
-
ÐÐ»Ñ Ð¿ÑимиÑивов Ñ Ð½ÐµÐ¹ оÑлиÑно ÑпÑавлÑеÑÑÑ Ð¾Ð¿ÐµÑаÑоÑ
typeof.У него две оÑобенноÑÑи:
- Ðн ÑÑиÑаеÑ
nullобÑекÑом, ÑÑо внÑÑÑеннÑÑ Ð¾Ñибка в ÑзÑке. - ÐÐ»Ñ ÑÑнкÑий он возвÑаÑаеÑ
function, по ÑÑандаÑÑÑ ÑÑнкÑÐ¸Ñ Ð½Ðµ ÑÑиÑаеÑÑÑ Ð±Ð°Ð·Ð¾Ð²Ñм Ñипом, но на пÑакÑике ÑÑо Ñдобно и полезно.
- Ðн ÑÑиÑаеÑ
-
ÐÐ»Ñ Ð²ÑÑÑоеннÑÑ Ð¾Ð±ÑекÑов Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ полÑÑиÑÑ Ñип из ÑкÑÑÑого ÑвойÑÑва
[[Class]], пÑи помоÑи вÑзова{}.toString.call(obj).slice(8, -1). ÐÐ»Ñ ÐºÐ¾Ð½ÑÑÑÑкÑоÑов, коÑоÑÑе обÑÑÐ²Ð»ÐµÐ½Ñ Ð½Ð°Ð¼Ð¸,[[Class]]вÑегда Ñавно"Object". -
ÐпеÑаÑоÑ
obj instanceof FuncпÑовеÑÑеÑ, Ñоздан ли обÑекÑobjÑÑнкÑиейFunc, ÑабоÑÐ°ÐµÑ Ð´Ð»Ñ Ð»ÑбÑÑ ÐºÐ¾Ð½ÑÑÑÑкÑоÑов. Ðолее подÑобно Ð¼Ñ ÑазбеÑÑм его в главе ÐÑовеÑка клаÑÑа: "instanceof". -
Ð, наконеÑ, заÑаÑÑÑÑ Ð´Ð¾ÑÑаÑоÑно пÑовеÑиÑÑ Ð½Ðµ Ñам Ñип, а пÑоÑÑо налиÑие нÑжнÑÑ ÑвойÑÑв или меÑодов. ÐÑо назÑваеÑÑÑ Â«ÑÑÐ¸Ð½Ð°Ñ ÑипизаÑиÑ».
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)