[] ==! [] Что случилось?

JavaScript

Я не могу припомнить, чтобы где-то видел это сравнение, и у меня не было четкого представления о принудительном преобразовании в то время, поэтому у меня есть эта статья. Думал, я бы расширил выражение для заголовка? Тогда вы ошибаетесь, давайте сразу перейдем к тому, как преобразуется [] == ![]:

  1. Поскольку приоритет оператора ! относительно высок, правая часть выражения сначала выполняет ![] для получения значения false, и выражение становится [] == false
  2. Принудительно присвойте false значение 0, выражение станет [] == 0
  3. После [] принудительного преобразования в исходный тип «» выражение становится «» == 0
  4. Преобразование "" в числовой тип, выражение становится 0 == 0
  5. Обе стороны имеют тот же тип, напрямую верните результат 0 === 0 TRUE

предисловие

Цель этой статьи — обобщить правила принуждения в js и несколько сценариев, которые запускают принуждение. В стандарте ES6 определены шесть примитивных типов, а именно Undefined, Null, String, Number, Boolean и Symbol.

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

Приведение между примитивными типами

Преобразование, которое происходит между примитивными типами, в моем личном понимании заключается в том, что другие типы преобразуются в типы String, Number или Boolean.

Преобразовать в строковый тип

Преобразование других типов-примитивов в тип String обычно происходит, когда по обе стороны от + находятся строки, а значение по другую сторону от + преобразуется в тип String. Рассмотрим следующий код:

var strAddNum = "test" + 1;
var numAddStr = 1 + "test";
var boolAddStr = true + "test";
var undAddStr = undefined + "";
var nullAddStr = null + "";
console.log(strAddNum);
console.log(numAddStr);
console.log(boolAddStr);
console.log(undAddStr);
console.log(nullAddStr);

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

  • Неопределенный, «неопределенный»
  • Ноль ноль"
  • Логическое значение, "истина" или "ложь"
  • Число, значение NaN, "NaN"
  • Число, значение +0 или -0, "0"
  • Число, значение +Бесконечность, "Бесконечность"
  • Число, значение -Бесконечность, "-Бесконечность"

Преобразование числа в строку для получения подробной информацииES2018 Раздел 7.1.12.1

Примечание. Тип символа нельзя преобразовать в тип строки.

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

В случае преобразования в числовой тип в таких операциях, как +-*/%, все операции, кроме +, будут преобразованы в числовой тип.В операции +, только если тип String не отображается с обеих сторон, значение будет преобразовано в Тип номера. . Ситуация с операцией + более сложная, и связанные с ней правила преобразования будут описаны позже. Рассмотрим следующий код:

var trueAddTrue = true + true;
var trueAddFalse = true + false;
var trueAdda0 = true + 0;
var nullAddTrue = null + true;
var undefinedAdd0 = undefined + 0;
var strAdd0 = "" + 0;
console.log(trueAddTrue);
console.log(trueAddFalse);
console.log(trueAdda0);
console.log(nullAddTrue);
console.log(undefinedAdd0);
console.log(strAdd0);

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

  • Не определено, NaN
  • Нуль, +0
  • Boolaen, значение true, 1
  • Логическое значение, значение ложно, +0
  • Строка, не может быть преобразована в число, нан
  • Строка, которую можно преобразовать в число, является соответствующим числовым значением (подробности см. в ES2018).7.1.3.1)

Примечание. Тип «Символ» также нельзя преобразовать в тип «Число».

Преобразование в логический тип

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

  • Undefined
  • Null
  • Число, +0, -0, NaN
  • Строка, строка длины 0 Эти ложные случаи четко указаны в стандарте ES.7.1.2

Объект приведен к примитивному типу

Алгоритм приведения объектов к примитивным типам в ES можно условно описать тремя ситуациями:

  1. Если для объекта установлено значение [Symbol.toPrimitive], вызовите эту функцию, если возвращаемое значение не является типом объекта, верните результат, в противном случае выдайте исключение TypeError.
  2. Если подсказка преобразования не указана, подсказка преобразования используется «по умолчанию».
  3. Если подсказка преобразования «по умолчанию», установите для нее «число».
  4. Когда указанное приглашение преобразования является «числом», сначала вызовите функцию valueOf объекта и оцените результат, если это примитивный тип, верните результат, в противном случае вызовите функцию toString объекта и оцените возвращаемый результат, если результат является примитивным типом, возврат, в противном случае исключение TypeError
  5. Когда указанное преобразование предложено сначала вызовите функцию TOSTRING, когда «строка» и определяет ее результат возврата, если это оригинальный тип, возвращает результат, или значение вызова функционирования объекта и определяет ее результат, если результат Оригинальный тип возвращается, в противном случае бросьте ненормальный типError

Среди трех вышеперечисленных ситуаций первая ситуация имеет наивысший приоритет, а вторая и три ситуации имеют одинаковый приоритет, который необходимо определить в соответствии со сценарием использования. Указанная подсказка преобразования указывается, когда алгоритм вызывается внутри по стандарту ES.

В первом случае только объект Symbol и объект Date имеют встроенный [Symbol.toPrimitive], а свойство для записи имеет значение false, перечисляемое — false, а настраиваемое — true. Неособые случаи приведения, возникающие при преобразовании объектов в примитивные типы, относятся ко второму, а третий встречается реже. Второго случая должно быть достаточно для нормальной работы по кодированию, третий случай встречается редко, подробности см. в стандарте ES.

var test = {
  [Symbol.toPrimitive]: function(hint) {
     console.log(hint)
  },
  valueOf: function() {
      console.log("valueOf")
  },
  toString: function() {
      console.log("toString")
  }
}
test + "";  //"default"
test * 0;   //"number"
String(test);   //"string"

кодовый порталВ приведенном выше коде указаны функции [Symbol.toPrimitive], valueOf и toString, которые определяют тестовый объект соответственно. Можно заметить, что функции valueoOf и toString не вызываются. Указанная функция [Symbol.toPrimitive] может принимать параметр приглашения, этот параметр Это обязательный запрос на преобразование при принуждении. Таким образом, мы можем возвращать разные значения в функции в соответствии с различными сценариями преобразования.

Приведение примитивного типа к объекту (упаковка)

Перед тем, как приступить к описанию этой проблемы, можно подумать о том, какие сцены будут принудительно вставлять примитивные типы в объект, на самом деле эта сцена почти везде в js-коде, рассмотрим следующий код:

var str = "testString";
str.replace("test", "");

Значение str, определенное в приведенном выше коде, является не объектом, а примитивным типом String, у которого, очевидно, нет метода для вызова.

На самом деле, когда выполняется str.replace, значение str будет преобразовано в объект, и будет получен объект экземпляра типа String, а на прототипе экземпляра определен ряд методов, и экземпляр не может После выполнения этой строки кода экземпляр будет переработан, поэтому str здесь по-прежнему является строкой.

Рассмотрим следующий код:

var a = 3;
a.fn = function(){};
a.fn();

Несколько сценариев принудительной конвертации

Обычно есть три сценария, в которых происходит принуждение в js-коде:

  • +операция
  • -,*,/,% операция
  • == сравнение
  • как условие суждения

+операция

Унарная + операция

При выполнении унарной операции + она будет принудительно преобразована в числовой тип, например

var a = {
    [Symbol.toPrimitive]: function(hint) {
        console.log(hint);  // number
        if(hint === "number") {
            return 2;
        } else {
            return 9;
        }
    }
};
console.log(+a);   // 2

var b = "3";
console.log(+b);    // 3

кодовый портал

Двоичный + операция

Двоичный + операция - это ситуация, в которой сложность вторая только до == сравнение в нескольких принудительных преобразованиях. Лично шаги преобразования суммируются следующим образом:

  1. Во-первых, приведите значения с обеих сторон к исходному типу (подсказка преобразования не указана, то есть подсказка преобразования является подсказкой по умолчанию);
  2. Если с обеих сторон есть типы String, они преобразуются в типы String, и возвращаются строки, склеенные с обеих сторон;
  3. Если второй не возвращается, значения с обеих сторон приводятся к числовому типу, и возвращается результат вычисления;
var a = "";
var b = {
    [Symbol.toPrimitive]: function(hint) {
        console.log(hint);  // "default"
        if(hint === "default") {
            return 2;
        } else {
            return 9;
        }
    }
};
var c = a + b;  //这里b转换为原始类型返回的是Number类型2,由于a是"",所以b被转换为"2",后与""拼接返回"2"
console.log(c); // "2"

var d = 3;
var e = {
    [Symbol.toPrimitive]: function(hint) {
        console.log(hint);  // "default"
        if(hint === "default") {
            return 2;
        } else {
            return 9;
        }
    }
};
var f = d + e;  //这里e转换为原始类型返回的是Number类型2,由于两侧均没有String类型,则至第3步,强制转换为Number后返回两侧相加的结果5
console.log(f); // 5

кодовый портал

-,*,/,% операция

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

  1. Преобразование объекта в исходный тип и указание подсказки преобразования как «число» при преобразовании;
  2. После преобразования в исходный тип преобразованный преобразуется в числовой тип в соответствии с исходным типом;
var a = 8;
var b = {
    [Symbol.toPrimitive]: function(hint) {
        console.log(hint);  // "number"
        if(hint === "number") {
            return 2;
        } else {
            return 9;
        }
    }
};
console.log(a-b);   //  6
console.log(a/b);   // 4
console.log(a*b);   // 16
console.log(a%b);   // 0

console.log(undefined * 0);   //NaN
console.log(null * -1); // 0
console.log(false * -1);    //0 
console.log(true * -1); // -1
console.log("1" * -1);  // -1

кодовый портал

== Сравнить

==Основы сравнения ===Сравнение

x === y, конкретные шаги сравнения следующие:

  1. Если типы x и y несовместимы, вернуть false;
  2. Если x и y имеют тип Number, вернуть false, если один из x и y равен NaN; вернуть true, если значения x и y равны; если x равно +0, y равно -0 или x равно -0, y равно +0 возвращает true, иначе возвращает false;
  3. Возвращает true, если x и y имеют тип undefined
  4. Возвращает true, если x и y имеют нулевой тип
  5. Возвращает true, если x и y имеют тип String и их значения совпадают, в противном случае возвращает false
  6. Если x и y имеют логический тип, их значения равны true или оба возвращают true, иначе возвращают false
  7. Возвращает true, если x и y имеют тип Symbol и их значения совпадают со значением Symbol, в противном случае возвращает false
  8. Возвращает true, если x и y имеют тип Object и их значение — один и тот же объект (ссылочный адрес тот же), в противном случае возвращает false

х == у правило

Хотя для сравнения == существует немного больше правил преобразования, на самом деле их всего несколько.Числовые типы с обеих сторон преобразуются в зависимости от того, какой тип соответствует, но некоторые из них, возможно, потребуется преобразовать дважды, как показано ниже:

  1. Если типы обеих сторон равны, результат === возвращается напрямую;
  2. Возвращает true, если x не определено, а y равно null или если x равно null, а y не определено
  3. Если обе стороны относятся к типу String и типу Number, преобразуйте тип String в тип Number и продолжайте использовать == для сравнения.
  4. Если на одной стороне есть логический тип, преобразуйте логический тип в числовой тип и продолжайте использовать == для сравнения.
  5. Если обе стороны имеют тип строки, числа или символа и тип объекта, преобразуйте тип объекта в исходный тип и продолжайте использовать == для сравнения.
  6. иначе вернуть ложь

Вот несколько сравнений, которые могут показаться несколько нелогичными.

"0" == false; // true
false == 0; // true
false == ""; // true
false == []; // true
"" == 0; // true
"" == []; // true
0 == []; // true
[] == ![];  //true

как условный приговор

Об этой ситуации сказать особо нечего, в основном, кроме undefined, null, +0, -0, NaN, "" эти шесть значений будут преобразованы в false, а все остальные случаи верны;

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

  1. if(...)
  2. for(...;...;...) второе условное выражение
  3. Условные выражения в while(...) и do...while(...)
  4. ...?...:...первое условное выражение в троичном выражении
  5. || и &&

В заключение

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