Поговорим о valueOf и toString

JavaScript

valueOf и toString являются методами Object.prototype. Как правило, он редко вызывается напрямую, но эти два метода вызываются, когда объект используется для участия в операции. Думаю, у многих возникают следующие вопросы:

  • Что имеет более высокий приоритет, valueOf или toString?
  • Все ли сценарии вызывают valueOf и toString

Объяснение концепции

  • valueOf: возвращает примитивное представление значения объекта.
  • toString: возвращает строковое представление объекта

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

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

valueOf — это метод Object.prototype.Объекты из Object будут иметь этот метод, но многие встроенные объекты переопределяют этот метод, чтобы удовлетворить фактические потребности.

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

  • Boolean
  • Null
  • Undefined
  • Number
  • String

Правила перезаписи для непримитивных значений (то есть объектов) следующие:

объект значение возвращаемого значения
Array сам массив
Boolean Логическое значение
Date Возвращает метку времени в миллисекундах
Function сама функция
Number числовое значение
Object сам объект
String строковое значение

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

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

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

  1. Прямое приведение к true (то же самое для типов-оболочек), без вызова valueOf и toString

преобразовать объект в число

Когда ожидается, что объект будет использоваться как число, например, участие в арифметических операциях и других операциях, методы valueOf и toString будут вызываться по очереди, когда объект преобразуется в число. Конкретные правила таковы:

  1. если объект имеетvalueOfметод и возвращает исходное значение (строка, число, логическое значение, неопределенное значение, ноль), затем преобразует исходное значение в число (если преобразование завершается неудачей, оно возвращает NaN) и возвращает число
  2. если объект имеетtoStringметод и возвращает исходное значение (строка, число, логическое значение, неопределенное значение, ноль), затем преобразует исходное значение в число (если преобразование завершается неудачей, оно возвращает NaN) и возвращает число
  3. Преобразование не удалось, выдает TypeError

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

  1. если объект имеетtoStringметод и возвращает исходное значение (строка, число, логическое значение, неопределенное, ноль), затем преобразует исходное значение в строку и возвращает строку
  2. если объект имеетvalueOfметод и возвращает исходное значение (строка, число, логическое значение, неопределенное, ноль), затем преобразует исходное значение в строку и возвращает строку
  3. Преобразование не удалось, выдает TypeError

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

объект возвращаемое значение toString
Array Строка, разделенная запятыми, например [1,2], возвращаемое значение toString равно "1,2"
Boolean "True"
Date Удобочитаемая строка времени, например «Вторник, 15 октября 2019 г., 12:20:56 GMT+0800 (стандартное время Китая)».
Function Строка исходного кода JS, объявляющая функцию
Number "числовое значение"
Object "[object Object]"
String "нить"

Подтвердить преобразование объекта в примитив

ValueOf и ToString нечего смотреть на то, что можно сказать на ежедневное развитие редко вызывается напрямую, но когда мы возражаем для использования в качестве исходного значения преобразования, но процесс преобразования также немного запутался.

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

Чтобы наглядно увидеть процесс конвертации внутри JS, я просто переписал и valueOf, и toString и добавил логи.

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
var b = new Boolean(false);

if (a) {
    console.log(1);
}
if(b) {
    console.log(2);
}

Вывод приведенного выше примера выглядит следующим образом:

1
2

valueOf и toString не вызываются в соответствии с правилами преобразования [object to boolean]

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

Пример 1

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function() {
    console.log('valueOf');
    return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function() {
    console.log('toString');
    return toString.call(this);
};
var a = {};
console.log(++a);

Результат выглядит следующим образом:

valueOf
toString
NaN

анализировать

  1. Метод valueOf возвращает сам объект, а не исходное значение, продолжайте выполнять
  2. Метод toString возвращает «[object Object]», которое является исходным значением (строкой), и преобразует строку в число NaN.

Пример 2

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return "1"; // 强制返回原始值
};
// 添加toString日志
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
console.log(++a);

Результат выглядит следующим образом:

valueOf
2

анализировать

  1. valueOf возвращает исходное значение (строку), преобразует строку непосредственно в число и получает 1

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

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

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};
var a = {};
alert(a);

Результат выглядит следующим образом:

toString
// 弹出[object Object]

анализировать

  1. Вызывается метод toString, и возвращается строка «[object Object]», и, наконец, объект преобразуется в эту строку.

Пример 2

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
    console.log('toString');
    return this;
};
var a = {};
alert(a);

Результат выглядит следующим образом:

toString
valueOf
Uncaught TypeError: Cannot convert object to primitive value
    at 1.js:16

анализировать

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

##[Special] Обработка при использовании оператора плюс для соединения строк и объектов

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

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
    console.log('valueOf');
    return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
    console.log('toString');
    return toString.call(this);
};

console.log("a" + {});

Результат выглядит следующим образом:

valueOf
toString
a[object Object]

сомневаться

"a"+ {}следует ожидать{}При использовании в качестве строки сначала следует вызвать метод toString, но это не так.

В заключение

Выводы, сделанные на основе данных поиска, следующие:

  1. Если один из них является объектом, следуйте процессу преобразования объекта в исходное значение (объект Date напрямую вызывает toString для завершения преобразования, другие объекты преобразуются через valueOf, и если преобразование не удалось, вызывается toString)
  2. Если оба являются объектами, оба объекта преобразуются в строки после шага 1.
  3. Два числа, выполнить арифметические операции
  4. Две строки, соединенные напрямую
  5. Строка и число, непосредственно объединенные в строку

вопросы интервью

var a = {};
var b = {};
var c = {};
c[a] = 1;
c[b] = 2;

console.log(c[a]);
console.log(c[b]);

отвечать

Поскольку ключ объекта является строкой, поэтомуc[a]а такжеc[b]серединаaа такжеbВыполняется преобразование [объекта в строку].

Согласно правилам преобразования,aа такжеbпреобразуются в[object Object],такc[a]а такжеc[b]Один и тот же ключ работает.

ответ输出两个2, окончательная структура объекта c выглядит следующим образом:

{
  '[object Object]':2
}

0.jpeg