什么时候toString()在javascript中隐式调用?

时间:2018-04-26 06:44:16

标签: javascript tostring

参考下面用Javascript编写的代码。



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




输出为"Condition is true"。看起来它调用toString()函数。但是如何?

当我用"=="替换"==="时,条件不会计算为true,这次不会调用toString()函数吗?

有人可以详细解释我的内容吗?

7 个答案:

答案 0 :(得分:1)

  

输出为“条件为真”。看起来它调用'toString()'   功能

每当您在具有不同类型的两个变量之间使用==运算符时,将在内部调用toString方法,该方法将强制转换一个member。看看type coercion

  

但是怎么样?

您正在为toString对象创建一个自定义a函数,该函数会在每次使用时更改它返回的内容,以使其满足所有两个条件。 您也可以使用valueOf方法。

  

===运营商怎么样?

否则,===运算符不会转换。

  

这意味着什么?

如果您使用===运算符,其中两个值不同,类型为===,则只返回 false

答案 1 :(得分:1)

执行==时,这不是一个严格的比较,因此它对条件a == 3 && a == 4的作用是首先比较a == 3。因为,它不是严格的比较,它会将a更改为字符串。由于toString()中有a,因此会将a的值从2增加到3,因此a == 3会导致true。然后,a == 4检查方式相同,这次a的值为3,因此当它检查a == 4时,通过调用{true会产生toString() {1}} 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');
}

答案 2 :(得分:0)

除了Mihai的回答,===是一个严格的类型检查等式运算符,它检查操作数的类型和值。

在您的情况下,a的类型是对象,而34是数字。因此,条件不会评估为true

答案 3 :(得分:0)

当你使用==时,它会检查对象是否有假值。这就是为什么你从== 4和= = 3得到真实。看看类型强制。它在比较它们时不会强制变量,这就是为什么你不能进入块语句

答案 4 :(得分:0)

您可以找到有关' =='的详细信息。和' ==='适用于以下链接的javascript: Equality comparisons and sameness

在此网址中,使用=='参考'松散平等部分。

在您的情况下,您的比较为== 3. a是对象,3是数字。因此,比较将发生在ToPrimitive(a)== 3. ToPrimitive(a)做的是尝试在A上调用a.toString和a.valueOf方法的不同序列。这就是你的toString函数的调用方式。

答案 5 :(得分:0)

从表面上看,您的问题看起来就像=====运营商之间的绝对差异,但实际上还有更多内容。

对于您的第一个问题,由于javascript是不是严格类型的语言,因此有2个运算符,==会尽可能将左操作数转换为右操作数而{{1}如果类型不同,===

除外,将给出false

更有趣的问题是调用NaN方法时。通常,当您通过键入对象文字或通过构造函数创建对象时,它将从Object继承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 becuae toString将导致对象本身。 valueOf默认提供什么?它可以取决于其原型链上的内容:

toString

因此,默认情况下,首选是使用对象的最近w.toString() //"[object Object]" u.toString() //"function (){}" u.prototype.toString.call(u) //"[object Function]" 方法。现在看看如果我们覆盖 BOTH toStringvalueOf会发生什么,让我构建这个对象:

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。要覆盖默认行为,您可以使用toStringtoString强制调用字符串,如示例所示。所以优先级列表如下:

自定义值>>自定义toString>>默认为toString>>>>默认值

答案 6 :(得分:0)

碰巧注意到toString是在插值字符串中调用的,它的执行优先于valueOf

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

console.log(`interpreted value: ${a}`); // interpreted value: call toString method