На первый взгляд ваш вопрос выглядит как явное различие между ==
и ===
операторами, но на самом деле есть еще кое-что.
По первому вопросу, поскольку 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