Когда toString () вызывается неявно в javascript? - PullRequest
0 голосов
/ 26 апреля 2018

Со ссылкой на код ниже, написанный на Javascript.

let a = {
    value: 2,
    toString: function() {
        return ++this.value;
    }
}
if (a == 3 && a == 4) {
    console.log('Condition is true');
}

Выход "Condition is true".Похоже, он вызывает функцию toString().Но как?

Когда я заменяю "==" на "===", условие не оценивается как истинное и на этот раз не вызывает toString() функцию?

Может кто-нибудь объяснить мне подробночто происходит под капотом?

Ответы [ 7 ]

0 голосов
/ 26 апреля 2018

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

По первому вопросу, поскольку javascript не строго типизированный язык , есть 2 оператора, == попытается преобразовать левый операнд в правый тип, если это возможно, тогда как ===выдаст false, если типы отличаются, за исключением NaN.

Более интересный вопрос - когда вызывается метод toString.Обычно, когда вы создаете объект, набирая литерал объекта или через конструктор, он наследует toString от объекта, вы легко проверяете это:

var u = function(){};
var w = {};
u.prototype.toString === Object.prototype.toString //true
w.toString === Object.prototype.toString //true as well

Теперь вы можете забыть, чтоэто также метод valueOf:

u.prototype.valueOf === Object.prototype.valueOf //true
w.valueOf === Object.prototype.valueOf //true as well

Но что он делает?Я указываю на себя:

w.valueOf === w //true
u.prototype.valueOf() === u.prototype //true as well

Поэтому, когда объект задан, первым выбором будет использование toString becuae valueOf, которое приведет к самому объекту.Что toString дает по умолчанию?это может зависеть от того, что находится в его цепочке прототипов:

w.toString() //"[object Object]"
u.toString() //"function (){}"
u.prototype.toString.call(u) //"[object Function]"

Поэтому по умолчанию первым выбором является использование ближайшего toString метода объекта.Теперь, чтобы увидеть, что произойдет, если мы переопределим ОБА valueOf и toString, позвольте мне построить этот объект:

 var x = {
    inner:10,
    ledger:[],
    result:[],
    timeout:0,
    toString:function(){
        console.log("String");
        clearTimeout(this.timeout);
        this.timeout = setTimeout((function(){
            this.result = this.ledger;
            this.ledger = []}).bind(this)
        ,0) ;
        this.ledger.push("toString");
        this.ledger.slice(-2);
        return String(this.inner);
    },
    valueOf:function(){
        console.log("Valueof");
        clearTimeout(this.timeout);
        this.timeout = setTimeout((function(){
            this.result = this.ledger;
            this.ledger = []}).bind(this)
        ,0) ;
        this.ledger.push("valueOf");
        this.ledger.slice(-2);
        return this.inner;
    }
}

Этот объект будет содержать "регистр", массивvalueOf или toString или оба вызывается во время преобразования типа.Это также будет console.log.Итак, вот некоторые операции, которые будут запускать преобразование типов, как ==:

 +x //10
//ValueOf

"5" + x //"510"
//ValueOf

x + [] //10
//ValueOf

x + "str"//"10str"
//ValueOf

x.toString() //"10"
//String

String(x) //"10"
//String

x + {u:""} //"10[object Object]"
//valueOf

Так что во многих случаях, если найдено значение по умолчанию , которое используется.Если правый операнд является строкой, то возвращаемое значение из valueOf преобразуется в строку, а не toString в объекте.Чтобы переопределить поведение по умолчанию, вы можете принудительно вызвать строку, используя toString или String(, как показано в примерах.Таким образом, список приоритетов выглядит так:

Пользовательское значениеOf >> Пользовательское значение toString >> Стандартное значение toString >>>> Стандартное значениеOf

0 голосов
/ 03 июля 2019

Случается, что toString вызывается в интерполированной строке, выполнено с приоритетом, чем valueOf

var a = {
    value: 1000,
    toString: () => 'call toString method',
    valueOf: () => 'call valueOf method'
};

console.log(`interpreted value: ${a}`); // interpreted value: call toString method
0 голосов
/ 26 апреля 2018

Подробную информацию о том, как '==' и '===' работает в javascript, можно найти по ссылке ниже: Сравнения равенства и одинаковость

В этом URL см. "Свободное равенство"используя == 'section.

В вашем случае ваше сравнение как == 3. a - это объект, а 3 - это число.Таким образом, сравнение будет происходить как ToPrimitive (a) == 3. То, что делает ToPrimitive (a), это попытка вызвать различные последовательности методов a.toString и a.valueOf на A. Вот как вызывается ваша функция toString.

0 голосов
/ 26 апреля 2018

проверяет, имеет ли объект ложное значение или нет, когда вы используете ==, поэтому вы получаете истину из == 4 и == 3. Посмотрите на приведение типа .Он не вызывает переменные при сравнении, и поэтому вы не можете попасть в оператор блока

0 голосов
/ 26 апреля 2018

Когда вы делаете ==, это не строгое сравнение, поэтому то, что оно делает для условия a == 3 && a == 4, это то, что сначала оно сравнивает a == 3.Поскольку это не строгое сравнение, оно изменит a на строку.И поскольку у вас есть toString() в a, это увеличит значение a с 2 до 3 и, следовательно, a == 3 приведет к true.Затем a == 4 проверяет аналогичным образом, и на этот раз значение a равно 3, поэтому, когда оно проверяет a == 4, оно приводит к true, вызывая функцию toString() a.

let a = {
  value: 2,
  toString: function() {
    return ++this.value;
  }
}
if (a == 3 && a == 4) {
    console.log('Condition is true');
}

Однако, когда вы используете ===, это работает как строгое сравнение, и тип LHS должен соответствовать RHS.Таким образом, a является объектом в LHS, а в RHS есть числовой тип, поэтому он дает false для a == 3 и, следовательно, a == 3 && a == 4

let a = {
  value: 2,
  toString: function() {
    return ++this.value;
  }
}
if (a === 3 && a === 4) {
  console.log('Condition is true');
} else {
  console.log('Condition is false');
}
0 голосов
/ 26 апреля 2018

В дополнение к ответу Михая, === является строгим оператором равенства проверки типов, который также проверяет тип операндов и значения.

В вашем случае тип a являетсяобъект, тогда как 3 и 4 являются числами.Таким образом, условие не оценивается как true.

0 голосов
/ 26 апреля 2018

Выход «Условие истинно».Похоже, что он вызывает функцию 'toString ()'.

Каждый раз, когда вы используете оператор == между двумя переменными разных типов, он вызывается внутренне toString методом, который приведет один member.Взгляните на приведение типа

Но как?

Вы создаете пользовательскую функцию toString для вашего a объекта, которыйизменяет то, что возвращает каждый раз, когда его используют, так что оно удовлетворяет всем двум условиям.Вы также можете использовать метод valueOf.

Как насчет оператора ===?

В противном случае оператор === не будет не делать преобразование.

Что это значит?

Если вы используете оператор === с двумя значениями различного типа ===, то просто вернет false.

...