Сколько способов JS определяет тип? Прочитав эту статью, вы узнаете!

внешний интерфейс JavaScript

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

тип данных

Типы данных в JS в основном делятся на две категории: примитивные типы (типы значений) и ссылочные типы. Общие типы данных показаны на следующем рисунке:

image-20200506103537269

Примитивные типы данных хранятся в стеке, а ссылочные типы хранятся в стеке как ссылочный адрес, который указывает на объект данных в куче. должен быть в курсеnullЗдесь мы считаем в примитивных типах, но вы используетеtypeofкогда ты узнаешь, что онobject, причина в том, что даже если он объект, он должен хранить в стеке адрес ссылки, но он пустой объект, поэтому этот адрес пустой, то есть он не соответствует никаким данным в куче, он не имеет данных в куче, существует только в стеке, поэтому здесь он считается примитивным типом. Ссылочный тип на самом деле в основномObject,Arrayа такжеFunctionЭто на самом делеObjectполученный.Более подробные сведения об этих двух типах памяти см. в этой статье.

image-20200506104330145

Давайте посмотрим на разницу между этими двумя типами:

примитивный тип

  1. Значение примитивного типа нельзя изменить, только переназначив. Попытка изменить его, как показано ниже, не сработает, но все переназначение сработает.

    image-20200506104958681

    image-20200506105044457

  2. Сравнение примитивных типов заключается в сравнении значений, если значения равны, они равны

тип ссылки

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

    image-20200506105513907

  2. При сравнении ссылочных типов сравниваются их индексные адреса, а не их значения. Например, следующие два объекта выглядят одинаково, но их ссылочные адреса не совпадают, но они не равны:

    image-20200506110135018

    Чтобы сделать их равными, вы должны напрямую преобразоватьbназначить какa, чтобы их ссылочные адреса были одинаковыми и равными.

    image-20200506110256501

преобразование типов

В JS преобразование типов выполняется при вычислении разных типов данных, как в следующем примере:

image-20200506110621714

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

неявное преобразование типов

преобразовать в строку

часто появляются в+операция, и один из операндов не является числовым типом

let s = 4 + 'px' + 5;
console.log(s);   // 4px5

s = 123e-2 + 'a';  
console.log(s);   // 1.23a

Преобразовать в числовой

Часто появляется в математических операциях, указывающих на объединение строк.+За исключением операций

let s = 'abc';
console.log(+s, -s); // NaN, NaN

s = ' 123 ';
console.log(+s, -s); // 123 -123

s = new Date();
console.log(+s, -s);  // 1588675647421 -1588675647421   (这个操作相当于取毫秒数)

Преобразование в логическую сцену

Часто появляется в if или логических операциях

let s = 'abc';
if(s) {
  console.log(s);  // abc
}

console.log(!!s);  // true

Следующие значения преобразуются в логическое преобразование вfalse, кроме этогоtrue:

  1. 0
  2. NaN
  3. '' (пустой строки)
  4. null
  5. undefined

== оператор

когда мы используем==При сравнении, если типы с обеих сторон разные, JS выполнит преобразование типов, а затем сравнит,===преобразование типов не будет выполнено, если===Типы данных с обеих сторон разные, возврат напрямуюfalse.

image-20200506112606774

Выше приведены лишь некоторые из случаев.Чтобы узнать больше, вы можете обратиться к следующей таблице, взятой из MDN. В этой таблице много содержимого, часть из которого прямо определяется спецификацией, напримерnull == undefined, а о логике и речи быть не может. Мы можем проверить эту таблицу, если не уверены, но ее не рекомендуется использовать в реальной разработке.==Да, потому что если вы неправильно запомните это отношение преобразования, это может привести к ошибкам, которые сложнее устранить. Обычно рекомендуется использовать его напрямую.===.

image-20200506111718423

Правила преобразования

В следующих таблицах приведены некоторые правила преобразования из JS Definitive Guide:

image-20200505185955549

image-20200505190049837

image-20200505190124871

явное преобразование типов

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

image-20200506113002845

преобразовать строку

Можно использовать явное преобразование в строкуtoStringметод, результат его выполнения обычно такой же, как иString()метод тот же. типа КоличествоtoStringМетод также поддерживает параметры, которые могут указывать базу для преобразования. На следующих диаграммах показаны некоторые примитивные типыtoString(),nullа такжеundefinedнетtoStringметод вызов сообщит об ошибке:

image-20200506113217062

типа КоличествоtoStringМетод поддерживает шестнадцатеричный формат:

image-20200506113346662

Значение революции

Преобразование в числовое значение очень простое, и часто используются эти два глобальных метода:parseIntа такжеparseFloat.

объект для строки

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

  1. value.toString()

    Это было сказано раньше

  2. '' + value. Это неявное преобразование, упомянутое ранее, ноvalueЕсли это объект, он будет преобразован в следующем порядке:

    1. сначала позвониvalue.valueOfметод, который возвращает значение, если значение является примитивом
    2. В противном случае позвонитеvalue.toStringметод, который возвращает значение, если значение является примитивом
    3. В противном случае сообщается об ошибке TypeError
  3. String(value). Это явное преобразование, упомянутое ранее Процесс аналогичен предыдущему, но вызовtoStringа такжеvalueOfпорядок разный.

    1. сначала позвониvalue.toStringметод, который возвращает значение, если значение является примитивом
    2. В противном случае позвонитеvalue.valueOfметод, который возвращает значение, если значение является примитивом
    3. В противном случае сообщается об ошибке TypeError

должны знать о том,DateОбъект немного особенный, он всегда звонитtoStringметод.

Давайте напишем кусок кода для проверки:

Object.prototype.valueOf = function() {
  return 'aaa';
}

Object.prototype.toString = function() {
  return 'bbb';
}

let a = {};
let b = '' + a;
let c = String(a);

console.log(b);
console.log(c);

Вывод приведенного выше кода, как мы и ожидали:

image-20200506160225229

значение поворота объекта

Существует два основных способа преобразования типа объекта в значение:

  1. +value
  2. Number(value)

Логика выполнения для обоих одинакова:

  1. сначала позвониvalueOfметод, который возвращает значение, если значение является примитивом
  2. В противном случае позвонитеtoStringметод, тоtoStringПреобразование возвращаемого значения в числовое значение

Как обычно, напишите пример, чтобы увидеть:

Object.prototype.valueOf = function() {
  return {};
}

Object.prototype.toString = function() {
  return 'bbb';
}

let a = {};
let b = +a;
let c = Number(a);

console.log(b);
console.log(c);

Вывод приведенного выше кодаNaN, это потому что мыtoStringметод возвращенbbbНет возможности преобразовать его в нормальное значение, принудительно преобразоватьNaN:

image-20200506160750545

Определение типа

Обнаружение типов — это проблема, с которой мы часто сталкиваемся, и во время интервью часто задают различные типы методов обнаружения.Ниже приведены несколько наиболее часто используемых типов методов обнаружения.

typeof

Наиболее часто используемая проверка типовtypeofсейчас:

let a;
typeof a;   // undefined

let b = true;
typeof b;   // boolean

let c = 123;
typeof c;   // number

let d = 'abc';
typeof d;   // string

let e = () => {};
typeof e;   // function

let f = {};
typeof f;   // object

let g = Symbol();
typeof g;   // symbol

instanceof

typeofСамый простой, но он может судить только об основном типе, если это объект, то он не может судить о том, что это за объект.instanceofМожно определить, является ли объект экземпляром определенного класса, это обнаружение фактически основано на объектно-ориентированной цепочке и цепочке прототипов.Для получения дополнительной информации о принципе instanceof вы можете прочитать эту статью. Вот пример:

let a = new Date();
a instanceof Date;  // true

constructor

constructorПринцип тот же, что и в предыдущемinstanceofВроде как, тоже на основе объектной ориентации и цепочки прототипов. Если объект является экземпляром класса, то его прототипconstructorНа самом деле он тоже указывает на этот класс, мы можем судить о егоconstructorчтобы определить, является ли он экземпляром класса.Конкретный принцип также подробно объясняется в статье, упомянутой выше.. Или используйте приведенный выше пример:

let a = new Date();
a.constructor === Date;  // true

использоватьconstructorОбратите внимание при оценке, если прототип наconstructorПри изменении это обнаружение может завершиться ошибкой, например:

function a() {}
a.prototype = {
  x: 1
}

let b = new a();
b.constructor === a;    // 注意这时候是 false

вышеfalseПричина в том, чтоconstructorЭто свойство на самом деле висит наa.prototypeНиже мы приводимa.prototypeПри присвоении значения оно фактически перезаписывает все предыдущиеprototype, который также охватываетa.prototype.constructor, В это время у него на самом деле вообще нет этого атрибута.Если у нас есть доступ к этому атрибуту, мы можем найти его только в цепочке прототипов, и мы найдем его в это время.Object:

image-20200506172606821

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

a.prototype.x = 1;

Если вы должны покрыть все, не забудьте поставитьconstructorдобавить обратно:

a.prototype = {
  constructor: a,
  x: 1
}

duck-typing

duck-typingПеревод "утиный тип", название довольно странное, оно означает животное, если оно похоже на утку, ходит как утка и крякает как утка, то мы думаем, что это утка. Другими словами, мы судим о том, является ли он уткой, по его внешности и поведению, вместо того, чтобы точно определить, являются ли его гены уткой. Этот метод, конечно, не является строгим с научной точки зрения, но в некоторых случаях он эффективен. В языках программирования это означает, что объект имеет определенные свойства и методы, чтобы определить, является ли он тем объектом, который нам нужен. Например, некоторые библиотеки с открытым исходным кодом будут иметь следующий способ записи, чтобы определить, является ли объект массивом:

function isArray(object) {
  return object !== null && 
    typeof object === 'object' && 
    'splice' in object && 
    'join' in object
}

isArray([]);  // true

Это делается для того, чтобы определить, является ли целевой объект массивом, определяя, содержит ли целевой объект методы, которые должен иметь массив. Это называется выглядеть как утка, и это утка. но у одного естьspliceа такжеjoinОбъект метода также может пройти этот тест, так что это не точно, а подходит только для некоторых сценариев.

Object.prototype.toString.call

Object.prototype.toString.callОн более точен и может использоваться для определения типа нативного объекта:

Object.prototype.toString.call(new Array());   // [object Array]
Object.prototype.toString.call(new Date());    // [object Date]

Этот метод возвращает[object XXX]Этот XXX является соответствующим названием конструктора. Но он может определить только местные объекты, оно бесполезно для пользовательских типов:

function a() {}
let b = new a();

Object.prototype.toString.call(b);   // [object Object]

Вы можете видеть, что для пользовательских классовaслучайb, мы останавливаемся[object Object], вместо того, что мы ожидали[object a].

Некоторые нативные методы: Array.isArray, Number.isInteger.

Чтобы решить проблему определения типа, JS также вводит некоторые нативные методы для обеспечения поддержки, такие какArray.isArrayа такжеNumber.isIntegerЖдать.Array.isArrayМожет использоваться для проверки, является ли объект массивом:

Array.isArray([]);   // true
Array.isArray(123);  // false

Number.isIntegerМожет использоваться для проверки, является ли объект целым числом:

Number.isInteger(1);     // true
Number.isInteger(-1);    // true
Number.isInteger(-1.1);  // false
Number.isInteger('aaa'); // false

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

подраздел

На самом деле в JS нет идеального метода обнаружения всех типов, конкретный метод обнаружения требует от нас выбора и выбора в соответствии с реальной ситуацией. Вот краткое изложение нескольких методов:

image-20200506180011564

Суммировать

  1. JS имеет два типа данных, примитивные типы и ссылочные типы. Ссылочные типы в основном являются объектами.
  2. когда мы используем+логическое суждение или==Существует неявное преобразование типов.
  3. Иногда неявные преобразования типов будут иметь неожиданные результаты.===, вместо==.
  4. Преобразование объектов в строки и числа может потребовать корректировкиvalueOfа такжеtoStringметод, порядок вызова зависит от конкретной сцены.
  5. В JS нет идеального метода определения типов, нам лучше выбрать конкретный метод определения в соответствии с нашими потребностями.

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

Добро пожаловать, чтобы обратить внимание на мой общедоступный номербольшой фронт атакиПолучите высококачественные оригиналы впервые~

Цикл статей "Передовые передовые знания":nuggets.capable/post/684490…

Адрес GitHub с исходным кодом из серии статей «Advanced Front-end Knowledge»:GitHub.com/Денис — см....