JS :: Fixing typeof

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Здравствуйте коллеги.

Наткнулся на интересную статью о том как люди делают свой typeof, который распознаёт Array, RegEx и т.д. Понравилась сама идея и статья, поэтому решил с вами поделиться.

Собственно вот: Fixing the JavaScript typeof operator.

UPD: Закодил и выложил на GitHub, если кому оболом писать, но хочется пощупать.
@GitHub
Забираем и запускаем: .\Examples\SRD.Type.Examples.htm

Хорошей вам жизни.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

UPD. Написал у себя в боге статью относительно типов в JS и их классификации (пока что Draft).
Кому интересно — welcome.
JS :: Types Inside. Часть 1. Теория [Draft]

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

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

Дальше, тем кому это интересно:

Вот как это можно использовать:

typeOf returns a Type instance with overriden valueOf which returns the fulll type name.
Value types

  • typeOf(true) == ’boolean’
  • typeOf(1) == ’number’
  • typeOf(1.0) == ’number’
  • typeOf(NaN) == ’number’
  • typeOf(’This is a native string.’) == ’string’
Reference types
  • typeOf() == ’undefined’
  • typeOf(null) == ’null’
  • typeOf(new String(’This is a boxed string.’)) == ’string object’
  • typeOf([]) == ’array’
  • typeOf({}) == ’object’
  • typeOf(MyClass) == ’function MyClass’
  • typeOf(AnonymousClass) == ’function anonymous’
  • typeOf(/s+/) === ’regexp’
  • typeOf(new RegExp(’w+’)) == ’regexp’
  • typeOf(window) === ’window’
  • typeOf(window.document) == ’htmldocument’
  • typeOf(window.document.body) == ’htmlbodyelement’
  • typeOf(Math) === ’math’
  • typeOf((’Test’).substr) == ’function substr’
  • typeOf((new String (’Test’)).substr) == ’function substr’
  • typeOf(window.document.getElementById(’console’)) == ’htmlcollection’
typeOf returns a Type instance. This is a Type instance members usage.
Value types
  • typeOf(false).isBoolean() == true
  • typeOf(1).isNumber() == true
  • typeOf(1.0).isNumber() == true
  • typeOf(NaN).isNumber() == true
  • typeOf(’This is a native string.’).isString() == true
  • typeOf(’This is a native string.’).isString().isNative() == true
  • typeOf(’This is a native string.’).isString().isBoxed() == false
Reference types
  • typeOf(undefined).isUndefined() == true
  • typeOf(null).isNull() == true
  • typeOf(new String(’This is a boxed string.’)).isString() == true
  • typeOf(new String(’This is a boxed string.’)).isString().isBoxed() == true
  • typeOf(new String(’This is a boxed string.’)).isString().isNative() == false
  • typeOf([]).isArray() == true
  • typeOf({}).isObject() == true
Classes
  • typeOf(MyClass).isType() == true
  • typeOf(MyClass).isType().classType().isAnonymous() == false
  • typeOf(MyClass).isType().classType().className() == ’MyClass’
  • typeOf(AnonymousClass).isType() == true
  • typeOf(AnonymousClass).isType().classType().isAnonymous() == true
  • typeOf(AnonymousClass).isType().classType().className() == null

Have a good life !

P.S. Я ни в коем случае не умоляю достоинств всех перечисленных библиотек, подходов, компиляторов. Они все хороши, и я обезательно ознакомлюсь с их содержанием, но данный пост не об этом. Данный пост о решении, которое тоже имеет место быть и имеет свои приемущества и недостатки.

typeOf(NaN) == ’number’
вы это серьезно...
про такие функции как isNaN и isFinite слышали? Как написали ниже почитайте нормально мануал по JavaScript!
typeOf(NaN) == ’number’
Ну так тип NaN есть Number. Попробуйие написать у себя в браузере: alert(typeof NaN);...
вы это серьезно...про такие функции как isNaN и isFinite слышали?
Про такие функции слышал, мало того исполльзовал в своей практике.
Только что открыл по ним мануал, почитал, ничего нового...

А Вы могли бы как то более внятно изъясняться, «вы это серьёзно» и про то слышал ли я о функциях isNaN и isFinite не несут никакой информации для меня. Можно поконкретнее, что именно Вас смущает ?

Попробуйие написать у себя в браузере: alert(typeof NaN)
это я прекрасно знаю, не надо и открывать браузер ))
Ну так тип NaN есть Number.
это так, но работа вашего typeOf не очевидна на мой взгляд, для NaN я б реализовал так чтоб typeOf(NaN) == ’NaN’, тоесть typeOf(5) == ’Number’ а typeOf(NaN) == ’NaN’.

Ага, теперь понятно.
Ну если следовать предложеному мной подходу, тогда лучше сделать так:
typeOf(NaN) == ’number’
typeOf(NaN).isNaN() == true
typeof(NaN).isFinite() == false

Если сделать так, то всегда можно будет определить, настоящий тип аргумента, т.е. то что находится «под капотом» в дескрипторе типа (всё таки ж typeof NaN == ’number’ и мало ли, возможно это где то пригодится).

Но если надо проверить isNaN() это или isFinite() - воспользоваться этими методами...
UPD: isFinite() будет излишним — т.к. если известно что это Number, то isFinite = !isNaN();

Хорошее замечание, спасибо ! Сейчас допишу два метода.

Ну я вчера с перепугу свою либу реализовал на проверку 14 типов даных в JavaScript и там как раз учел

typeOf(5) == ’Number’ а typeOf(NaN) == ’NaN’

Ну isFinite() точнее нужен на проверку числа )) тоесть она будет исключать NaN, Infinity, -Infinity

и это точно также нарушает стандарт :)
почему я и говорю что такие идеи имеют место быть

Да там много ошыбок в стандарте...

100%, если бы там всё было правильно изначально реализовано, не пришлось бы дописывать подобные «костыли» :)

интересную статью о том как люди делают свой typeof
что!? опять!? Видимо Вы 2009-2011 года пропустили... А ведь хорошие времена были: все писали свои классовые обертки с наследованием, клонирование, обертки под DOM, делали типизацию над typeof, перезагрузку методов, дефолтные параметры функций, проверку типов и тому подобные приблуды...эх романтика :D хотя в этом случае слегка расширенную типизацию иногда юзаю по сей день на битовых масках для входных параметров функций, но дожили только:
TYPE_ARRAY, TYPE_BOOLEAN, TYPE_DATE, TYPE_ERROR, TYPE_FLOAT, TYPE_FUNCTION, TYPE_INT, TYPE_MAP, TYPE_NUMBER, TYPE_OBJECT, TYPE_PLAINOBJECT, TYPE_REGEXP, TYPE_SET, TYPE_STRING, TYPE_SYMBOL, TYPE_ITERABLE, TYPE_WEAKMAP, TYPE_WEAKSET
Понравилась сама идея и статья
идея стара как мир js, не сосчитать сколько раз у js-dev были влажные мысли на его счет- три раза перепроверял дату этого поста :)

на самом деле то что апроачи старые, это еще не значит что им нет места быть.

для меня самого свой тайпоф очень странная вещь, в которой я никогда не нуждался, но это не значит что в этом не нуждаются другие.

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

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

кстати то что люди используют последнии/современные технологии аж никак не гарантирует качество продукта на выходе.

Все новые вещи — это обёртки на базовыми возможностями языка. Иногда очень удачные, берущие на себя рутину и дающие возможность девелоперу сосредоточиться на решении бизнес задач, перевести его не уровень, на котороом он опреирует оъбектами большей мощности. К примеру зачем писать свою сортировку, если она уже 1000 раз написана. И девелопер уже мыслит не как организовать циклы, быстро отсортировать занчения и другие низкоуровневые вещи, а как опрерировать отсортированными коллекциями.
Но, как показывает практика, иногда приходится спускаться вниз на один или более уровней абстракци. Причины разные, баги в фреймворках, нужно сделать, что-то что не вписывается в возможности текущей модели и т.д. Т.е. фундамента не хватает, тогда надо строить совй фундамент. Что бы его строить, нужно владеть инструментом.

Как то так.

то!? опять!? Видимо Вы 2009-2011 года пропустили...
Да, пропустил, тогда уже основательно на back end переключился :)
Вот сейчас восполняю, смотрю к чему это всё пришло после 2006 — 2008 :)
хотя в этом случае слегка расширенную типизацию иногда юзаю по сей день на битовых масках для входных параметров функций, но дожили только:
Т.е. всё таки есть какой то свой код, который детектит тип и возвращает что-то отсюда ?
TYPE_ARRAY, TYPE_BOOLEAN, TYPE_DATE, TYPE_ERROR, TYPE_FLOAT, TYPE_FUNCTION, TYPE_INT, TYPE_MAP, TYPE_NUMBER, TYPE_OBJECT, TYPE_PLAINOBJECT, TYPE_REGEXP, TYPE_SET, TYPE_STRING, TYPE_SYMBOL, TYPE_ITERABLE, TYPE_WEAKMAP, TYPE_WEAKSET
Т.е. всё таки есть какой то свой код
угу, не магия же, несколько функций есть для возврата расширенного типа, либо битовую маску всех типов ну и маску в массив строк.
В принципе, я не говорю что это никчемная практика, но она вряд ли может быть интересной в 2016 году, ее то разобрали по косточкам в далекие времена все кому не лень... да и в офисном продакшене могут не понять адепты тупоскрипта :)

Спасибо за внятный ответ.

В принципе, я не говорю что это никчемная практика, но она вряд ли может быть интересной в 2016 году,
Ага, т.е. сейчас все перешли на babeljs.io и другие компиляторы (я ж правильно понимаю, babel — это компилятор, который ECMA-262 6.0 компилирует в JS совместимый с ECMA-262 5.1 ? А вот уже в ECMA-262 6.0 решены вопросы с типами и всё работает как надо ? Т.е. там уже можено вызвать Object.is, который правильно проверяет null. Есть поддержка лямбд, async / await и т.д. Т.е. на классике уже никто не пишет ?
да и в офисном продакшене могут не понять адепты тупоскрипта :)
:)))

Странная логика. Сами вначале пишут, что JS заточен под утиную типизацию. Но им нужна строгая, поэтому хотят её сэмулировать. Так если вам нужна строгая типизация, то и возьмите для разработки язык изначально предназначенный для этого.

А что, есть какие то альтернативы под браузер ?
Насколько мне известно Web Assembly никем пока не поддерживается. Да и для других целей он...

Ну раз для браузера, то там мало задач где это в действительности требуется. На ум приходит как раз только полиморфизм. Но и то это только для либ актуально, чтоб поддерживать удобство. А так в самих приложениях можно просто договорится и придерживаться единого стиля. Всё, проблема отпадает сама собой

Ну раз для браузера, то там мало задач где это в действительности требуется.
Ну смотря что писать. Если блымалку для кнопки, то да. Но если это какой-то rich UI web app, то совсем другие требования и подходы.
А так в самих приложениях можно просто договорится и придерживаться единого стиля.
Это если вас в комманде 2-3 человека, но если комманда поболее то договоры и прочие штуки как показывает практика не работает, проверено не однократно. Должен быть какой-то тогда тул, который следит за code style, code rules и т.д., аналог Resharper, StyleCop и т.д.
Должен быть какой-то тогда тул, который следит за code style, code rules и т.д.
ESLint или JSHint например?

Сразу хочется высказать свою точку зрения относительно duck-typing, строгой типизации и т.д.
В JavaScript лино я рассматриваю проверку типов как:
— Удобный способ проверить на наличие группы методов (типа bulk duck-typing)
— Проверить примитивные типы: String, Boolean, Number, ...
Поэтому хочу, что бы мне было удобно, что бы я не писал 100500 проверок, а написал одну строчку кода:

Example #1

// We sure that string contains split, join, toLowerCase and many other built-in methods
//   and we can simply can check object type instead of check all methods separately.
if(typeOf(anyStringNativeOrWrapped).indexOf('string') > -1)
{
  // I'll work with this guy as with a string, no matter native or wrapped
  var replaced = anyStringNativeOrWrapped.split('.').join('/');
  return replaced.toLowerCase();
}

Теперь давайте посмотрим что получится если использовать чистый duck-typing.
Example #2

// We need to check that all methods are exists before call them.
// If operation is atomar, then all required methods should be checked before continue execution.
// But in our case we want to apply only that methods which are exits inside an object.
if(typeof anyStringNativeOrWrapped !== 'undefined'
  && anyStringNativeOrWrapped !== null)
{
  var result = '';
  if(anyStringNativeOrWrapped.split instanceof Function 
      && anyStringNativeOrWrapped.join instanceof Function)
  {
    result = anyStringNativeOrWrapped.split('.').join('/');
    if(anyStringNativeOrWrapped.toLowerCase in Function)
    {
      result = result.toLowerCase();
    }
  }

   return result;
}

Не хочу никому ничего навязывать, или кого то в чём то убеждать, но ИМХО мне первый вариант более быстрый при написании кода, и легче для понимания. Другое дело, что второй более надёжный, т.к. проверяется наличие каждого метода, но что нам мешает в первом случае делать String.prototype.method.call, для повышения надёжности, и гарантии, что метод есть и он вызовется...

Та нет же, не так. Без стрикта null == undefined , и Object.is откройте для себя наконец.

Без стрикта
В некоторых случая strict is required. В частности если пишешь под Win Phone, на JS + HTML5.

А пишу я typeof variable == undefined && variable !== null вместо variable != null принципиально, что бы была, у того кто смотрит код, ясность. Вначале достаётся тип объекта и считается равным, если либо это undefined и object с reference = 0 либо это objectы и их references равны либо это value type и тогда их значения равны...или начинаем пытаться сконвертить тип одного из операндов и потом опять сравнить.

Т.е. == работает как то так:
1. Достать дескриптор типа 1
2. Достать дескриптор типа 2
3. Если дескрипторы типов равны, то
3.1. Если это reference type сравнить reference и вернуть резултат сравнения
3.2. Если это value type сравнить значения и вернуть результат сравнения
4. Если дескрипторы типов не равны
4.1. Если дескрптором типа 1 является undefined
4.1. Если дескриптор типа 2 тоже undefined вернуть true
4.2. Если дескриптор типа 2 Object
4.2.1. reference == 0 вернуть true
4.2.2. Если reference != 0 вернуть false
...

Но когда пишешь явно, что мол это и не undefine и не null, то это понижает попрог вхождения, для тех кто не знает таких подробностей и соотвтетсенно понижает кол-во возникновения ошибок. Если учесть что в бывает, что в комманде не все Senior JS девелоперы, есть Juniorы или вообще какой то BackEndщик залез подправит пару строк ( :))) ), то это даёт человеку чёткое представление, что в коде происходит. А это == тех кто на JS пишет не регулярно, сбивает с толку. Классический C ориентрованные девелопер чётко себе в голове представляет, что когда мы делаем == - сравниваются ссылки на объекты, если мы делаем аналог equals — он уже сравнивает содержание... Т.е. в JS всё на оборот, == - наоборот сравнивает содержание, что опять же повторюсь, non regular JS девелоперов сбивает с толку. Плюс cо стриктом работает не так и и.д, что понижает надёжность продукта в целом, т.к. является потенциальным местом для возникновения багов.
Можно сказать, дескать, так а какого на проекте нет dedicated JS Senior девелопера, на что я всегда отвечаю, что мир не идеален и да, это не есть хорошо, но это бывает сплошь и рядом. И не всегда квалификация Senior JS Developerа, соответстует его реальным знаниям. Как правило она не соответствует его «нашивкам», т.к. в FrontEnd идут в основном те, кому лень изучать глубины (опять же не все и не всегда и среди нас тут таких нет). Но многие JS девелоперы, не знают ничего ни о памяти ни о указателях, дескрипторах и т.д. В последние годы FrontEnd dev — это человек, который хочет по быстрому научиться делать сайты. Нахватался врхов, выучил фреймворк какой то и думает что он всё понял (наивный). Это потом он уже понимает, что для того что бы хорого делать сайты, надо учиить технологии, проникать в глубины... Поэтому я стараюсь писать как можно поще чтобы даже non regular JS понял что тут не должно быть undefined. Так же это не null.

Как то так.

и Object.is откройте для себя наконец.
For non-ES6 browsers.
Object.is() is a proposed addition to the ECMA-262 standard; as such it may not be present in all browsers.
...

Ужас просто, мы все умрем ))

Сори, про скрещивание сениоров с юниорами при фиксинге нулов в жс не прониклась, это хобби и мне глубоко толерантны такие трудности. Вообще мне эта тема нравится больше:

Классический C ориентрованные девелопер чётко себе в голове представляет,

Мне кажется, он максимум представляет себе какой endian на конкретной платформе использовать, а тупеов — от лукавого, распространямая патчем к определнной версии гэцэцэ. :)

Мне кажется, он максимум представляет себе какой endian на конкретной платформе использовать, а тупеов — от лукавого, распространямая патчем к определнной версии гэцэцэ. :)
Если кажется, то Вы сами знаете что делать... :)
Дело в том что в современной Outsource компании бывает так, что C девелопер пишет и на JS в том числе... Так мало того даже в продкутовых компаниях такое встречается. Возьмите ту же Hola.

Но тем не менее я имел немного другое (простите за не точность в формулировке).
Классический С девелопер — имелось ввиду девелопер который пишет на языках C подобным синтаксисом, там на C#, C++, Java... Не правильно выразился. Так вот например программист на C#, а если ещё и Web .NET Dev, вполне себе заходит и подаправляет «пару строк» в JS файлах...

C девелопер пишет и на JS в том числе
Классический С девелопер — там на C#, C++, Java
заходит и подаправляет «пару строк» в JS файлах

Смерть человекам !

Ну вырывать фразы из контекста и этим «жонглировать», как то не очень ИМХО, это удел политиков и им подобным третьесортных людей, манипуляторов... Думалось тут технари участвуют в обсуждени... Или я ошибся ?

То что пишете Вы.

Классический С девелопер — там на C#, C++, Java
Оригигал.
Классический С девелопер — имелось ввиду девелопер который пишет на языках C подобным синтаксисом, там на C#, C++, Java... Не правильно выразился.
null == undefined
и в стрикте, потому что
==
это не строгое сравнение.
null !== undefined
и не в стрикте, потому что сравнение строгое. Стрикт нужен для других вещей.

Речь об strict equality и была... синяя кепка, да но синяя, и вообще кепка )))

100%

11.9.3 The Abstract Equality Comparison Algorithm

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

If Type(x) is the same as Type(y), then
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
...

(www.ecma-international.org/ecma-262/5.1/#sec-11.9.3)

Еще чуть чуть и откроем implicit coercion, еще постов 200 и перейдем к более сложным типам..

Хорошая статья, спасибо.

Точнее тема

if(typeOf(anyStringNativeOrWrapped).indexOf(’string’) > −1)
if(anyStringNativeOrWrapped.split instanceof Function
&& anyStringNativeOrWrapped.join instanceof Function)

А если нет? То что, ничего не выполнять? :) Но это такая же ошибка как мьютить блоки try-catch
Уж лучше пусть валится ошибка. Тогда больше обратит на себя внимания. Придётся отловить на этапе написания.

А если нет? То что, ничего не выполнять? :)

Возможно пробросить custom exception...
Или Вы предлогаете клиенту валить непонятные для его понимания сообщения... Не есть правильной ИМХО.

К тому же возникновение и обработка exception (error) достаточно затратная операция я Вам скажу... Уже если возможно как то её избежать, то было бы не плохо... Покрайней мере если это не сломает структуру кода. Некоторые ф-ции например делают проверки, и возвращают некую структуру с внятным сообщением об ошибке, которая потом пробрасывается по цепочке на UI...
По разному бывает...

А что мешает избежать ? String.protype.split, Array.prototype.join вместо непонятных энистрингджоинизфункшн.

Так это же статика. Я имею ввиду String.prototype.split, etc... А что в эту статику передавать ?
Вы так предлогаете ?

function (anyStringNativeOrWrapped)
{

  var result = String.prototype.split.call(anyStringNativeOrWrapped, '.');
  result = String.prototype.join.call(result, '/');
  result = String.prototype.toLowerCase.call(result);

  return result;
}
Если так, то это приведёт к:
— Если в anyStringNativeOrWrapped ссылка на объект, то превый же split вернёт [Object object]... Ну и т.д. в итоге функция будте не правильно работать.
— Если value type, Function — скастится к стрингу и дальше всё отработает корректно
и т.д.
Но object сразу же даст фейл, причём не отлавливаемый фейл, просто куда то будет писаться ’[object object]’ и все будут думать что всё в порядке, пока не посмотрят логи или какой то разъярённй кастомер не поднимет шум, из-за того, что не понимает почему его постоянно просят ввести ’[object object]’...
Более правильное поведение ИМХО (в зависимости от контекста):
— проверить тип, если не строка, не важно, native, boxed — всё или возварщаем error status, или throw new Error(’Invalid type parameter’)
— используем какое то дефолтное значение

1. у String нет join,
2. почему в Вашей супермегалибе value ’[object object]’ вообще непонятно.
3. Сделайте новую версию js , которая будет поддерживать новый мегастандарт и революционный подход, назовите его srdec.js, будет круто.

Откройте уже ради бога мануал по js.

Думаю мануал стоит почитать Вам...
Пойдём по пунктам.

1. у String нет join,
var result = String.prototype.split.call(anyStringNativeOrWrapped, ’.’);
Специально, для тех кто ошибся форумом или не внимательно читает RFC объясняю, метод String.prototype.split — возвращает объект типа Array...
Т.е. в result после этой операции будет находиться массив...
Для которого потом будет вызван метод join...
result = String.prototype.join.call(result, ’/’);
String -> Array (тут то можно быдо уже догадаться, или AI только у роботов ? Вообще мне Вас жаль, Вы смотрете не суть идеи, а на опечатки...)

Надеюсь прояснил Вам значение этого кода ?
Поехали дальше...

2.

2. почему в Вашей супермегалибе value ’[object object]’ вообще непонятно.
Какое отношение это имеет к моей либе ?
Вы на код смотрите или в небо ) ?
Возвращаемся к этой строке...
var result = String.prototype.split.call(anyStringNativeOrWrapped, ’.’);
split в начале своей работы вызовет toString() у anyStringNativeOrWrapped (т.к. это не нативная строка... надеюсь Вы понимаете суть, если нет, забудьте об этом посте и примитесь наконец то за изучение JS... ).
toString() вернёт ’[object Object]’.
Затем он попытается его просплитить по точке. Их там там нет, надеюсь это понятно и в итоге в result получим array с одним строковым занчением ’[object Object]’.
Потом join вернёт строку ’[object Object]’.
Ну и в конце будет вызван для неё toLowerCase().

Хух... Шо ж туго то так у Вас с мышлением, всё надо объяснять как в деском саду...

Вы можете корчить рожи и т.д.
Но на простом примере это выглядет так:
Вам заказчик дал ТЗ, а вы ему — у тебя тут запятая не там стоит...
Котекст не тот.

ИМХО «still thinking» здесь не совсем уместно, оба языка были выпущены в 1995ом :)

Ключевые слова сарказма — последние три )

Sarcasm not detected, sorry ;( :)))

Незнание ни первого ни второго.. соболезную

Вы не знаете ни Java ни JavaScript ? Так а что Вы тогда делаете в этом топике ?

Незнание ни первого ни второго.. соболезную
Вы меня тоже насмешили... )))

Понял Вашу шутку, после того как вспомнил о существования бестселлера «Thinking in Java» :)
Сразу понял всё буквально.
Посмотрел на дату выпуска обоих языков — в один год. Поэтому still thinking не подходит. Если бы Java вышла на много раньше, то тогда можно было бы говорить что JS для тех кто still thinking... Это с точки зрения временного анализа.
С точки зрения семантического анализа.
JS не для тех кто still thinking in Java. Всё таки Java девелопер мыслит больше в терминах интерфесов, ООП и т.д. в отличе от JS девелопера, который думаеть по другому )) Поэтому Ваш пост заставил меня задуматься, что либо я чего то не знаю, либо Ваше утверждение не верно.

Но теперь всё стало на свои места ... sarcasm detected :)

Ну если на объект стринг вернет что это тип стринг могуть траблы.

Лично мне инстансоф и иногда тайпоф, хватало на все случаи жизни

Не совсем понял про объект стринг. Можешь пояснить ?

var foo = new String("bar“) // object
var foo = “bar” // string

Ну если на объект стринг вернет что это тип стринг могуть траблы.
var foo = new String("bar") // object

Ну в этом случае проблем не будет.

typeOf(new String('This is a string.')) //string

typeOf здесь предложенная в статье реализация fixed typeof.

Проблемы будут когда вы этот стринг передадите в другую либу, и она с вероятностью в 99 процентов примет это за объект (и будет права кстати) и очень часто примет за конфиг, а вы будете смотреть потом и не понимать в чем дело, ведь вы делаете все как в доке

Проблемы будут когда вы этот стринг передадите в другую либу, и она с вероятностью в 99 процентов примет это за объект (и будет права кстати)
Потреял нить, простите. А при чём здесь другая либа ? Т.е. как определит тип другая либа, это не есть область ответственности метода typeOf — это ответсвенность другой либы. Я к тому что можно сделать так:
var strOne = 'The string.', 
    strTwo = new String('The string.');

if(typeOf(strOne) === 'string')
{
   alert(strOne.substr(1, 1));
}

if(typeOf(strTwo) === 'string')
{
  alert(strTwo.substr(1, 1));
}
Если нам нужно вызывать какието методы у строки, то нам не важно — там действительно нативная строка или boxed нативная строка. Там движок JS уже сам решит, что делать, просто вызвать метод или сделать boxing, а потом уже вызвать метод. Но мы получаем выгоду в виде определения некого абстрактного типа ’string’. И нам не надо делать 2 проверки на нативную строку и на boxed строку:
if(str instanceof String || typeof str === 'string')
{
  // This is a string. And we can use any string methods like a: substr, etc.
}

Но если в каком то конкретном случае принципиально: нативная это строка или boxed строка, то тогда естественно этот метод не подойдёт.
Данный подход не претендует, полностью заменить instanceof, typeof ИМХО, в некоторых случаях он не подойёт. Поэтому я рекоменудю им пользоваться с умом, там где это уместно.

Как то так.

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

Думаю, тут наверно просто нужно «правильно» создвать объекты, что бы third party с ними нормально работали. Но да, если там скажем какой враппер над third party и например приходит в него не контролируемый параметр типа стринг и нам потом надо передать его third party компонениту, то надо проверить тип при помощи instanceof, typeof или других подходов и потом в случае необходимости преобразовать к ожидаемому и передать дальше по цепочке...
Это имелось ввиду ?

чтото типа того.
грубо говоря я о:

var regularString = 'param1';
var stringAsObject = new String('param1');

thirdpartyLib.build(regularString); // works fine
thirdpartyLib.build({name: regularString}); // works fine
thirdpartyLib.build(stringAsObject); // Error

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

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

и в итоге ваш вариант тайпофа будет очень сильно мешать

А что нам мешает сделать так:

	function typeOf(obj)
	{
		var result = typeof(obj);

                if(obj instnaceof String)
                {
                      result = 'string object';
                }
		else if(result !== 'undefined')
		{
			result = Object.prototype.toString.call(obj).match(/\s([^\]]*)/)[1].toLowerCase();
		}

		return result;
	}

И потом использовать так:

   var strAsStr = 'The string as string',
       strAsObj = new String('The string as object');

// If required granulated string detection
if(typeOf(strAsStr) === 'string')
{
  // Will be executed only for the native string.
}

if(typeOf(strAsObj) === 'string object')
{
  // Will be executed only for the boxed native string.
}

// If required abstract 'string' type detection
if(typeOf(strAsStr).indexOf('string') > -1)
{
  // Will be executed when no matter is it a native string or a boxed native string.
}

if(typeOf(strAsObj).indexOf('string') > -1)
{
  // Will be executed when no matter is it a native string or a boxed native string.
}
 

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

А что за история ? Можно ссылку ?

ну раньше undefined можно было переопределять, то есть присваивать ему значения

Спасибо, не знал о таком ньюансе.
Проверил только что в Chrome (Version 51.0.2704.103 m (64-bit)), IE (Version 11.420.10586.0) — не репродюсится, strict mode не включал.

уже пофикшено, на сегодня по идее еще в ИЕ8 присутствует.
в результате этого проверка на undefined до сих пор многие по привычке делают через тайпоф

Реальная беда это тайпоф от нулл, это реальный баг. А все остальное работает как и должно

А можно подробнее?
typeof null -> «object»
Что именно считать багом?

typeof null -> «object»
это баг джаваскрипта. в стандарте есть тип null, и он должен вернутся в результате этой операции, но к сожалению это историческая бага.

Ну цей тип з’явився в сучасних стандартах вже

Когда последний раз ES3 считался современным?

Да, действительно в спецификации есть. Просто никогда не встречался с проблемой, связанной с этой особенностью.
А есть пример ситуации из жизни, в которой эта ошибка может вызвать боль?

Боль в том что результат возвращенный от тайпоф ввиде ’object’ требует дополнительной проверки на то что это таки объект

Думаю просто нужно исользовать разные подходы для проверки null и object типов.

  if(obj === null)
  {
    // This is a null.
  }
  else if(obj instanceof Object)
  {
    // This is an object.
  }

А вообще как то криво получается. Более правильно ИМХО (и в других языках) когда null рассматривается как нулевой указатель. Т.е. есть например var obj = null.
Так вот, тип obj — object, но переменная obj никуда не ссылается. И если сделать строке str = null, то тип str тип уже будет не string, а object, и в str будет нулевой указатель. Т.е. это более правильно с точки зрения Машины Тьюринга и физической реализации архитектуры компьютера.

Только что осознал, как мне кажется, задумку автора JS.
Всё таки JS скриптовый, абстагирующий программиста от железа язык. Поэтому догадываюсь что с null они поступили следующим образом:
1. Создали в памяти статичекский объект с [Class] null
2. Если в коде встречается var obj = null. Они просто пробрасывают указательнь на статический объект из п.1.

Т.е получается такая себе эмуляция NullReference, где вместо указателя с 0 адресом, указатель на статический null объект.

Ну и как бы typeof должен был бы это детектить... но видимо они там какойто if забыли, и он видит что это некий объект, который ссылается на некий адрес в памяти (действительно, чем не объект), но не проверяют, что он таки ссылается не на некий объект, а на null объект ну и отдают ’object’...

Понятно.
Они просто забыли сделать проверку, а не null ли это ? :)))
Проверили, что объект, а проверить reference == 0 забыли :)


null (JSVAL_NULL) was the machine code NULL pointer. Or: an object type tag plus a reference that is zero.
А вообще как то криво получается.
вот-вот. вроде бы простая вещь, а в итоге того через одно место можно написать :(

Вот это какраз самый страшный баг... Который 100 ран не репроюдсится, а на 101ый что-то начинает работать не так как в спеке.

ну, его уже пофиксили в движке.
очередной апдейт и всё норм
UPD и кста, наоборот — первые 130+ раз как раз неверно, а потом нормально уже.

var source = new String("foo");
var target = "foo"
if (typeOf(source) === 'string" && source === target) {
  // все таки вони різні, стрінги ці ;)
}

они вообще разные. одно объект-обертка, второе — примитив. когда вызываются методы примитива автоматом создается объект-обертка (boxing) значения которого (toString) возвращает примитив. по окончании вызова объект-обертка уничтожается (unboxing). создавать новые строки через new String — это плохая идея.

Так я про це і кажу, Юра) А ця функція typeOf каже, що вони — однакові)

Я не спорю, написал более развернутый комментарий с объяснением в поддержку твоего =)

Гляньте на дату статті — серпень 2011 року — її вже можна вважати неактуальною. У вересні 2012 якраз вийшов TypeScript. Редактор, який розуміє TypeScript, підкаже що у вас є помилка з типами ще на етапі написанні коду (до компіляції в JavaScript).

TypeScript також вже зараз підтримує стандарти ES2015 та навіть деякі фішки із ES2016.

До речі, найкращу підтримку TypeScript має Visual Studio та VS Code (VS Code безкоштовний, легкий та працює навіть на Linux).

Число проектов, пишущихся или уже написанных на тайпскрипт, по сравнению с числом проектов написанных на чистом джаваскрипт, стремится к нулю.

Якщо ви напишете у файлах TypeScript на 100% чистий JavaScript, то він буде працювати справно. Тобто ви можете хоч одну єдину фічу використовувати з усього TypeScript — такий код буде працювати без проблем.

Значит Вам не сюда, проходом мимо... Спасибо.

Розкажете це мені, коли я зайду на вашу сторінку у ФБ, ВК і так далі. А тут я таки сам буду вирішувати куди і коли мені проходити.

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

А вы у нас уже познали дзен?))

А какое отношение это имеет к дзен ? ))

Підписатись на коментарі