资讯专栏INFORMATION COLUMN

toString方法和valueOf方法以及Symbol.toPrimitive方法的学习

el09xccxy / 1471人阅读

摘要:方法和方法介绍方法和我们知道在中,一切皆为对象。每个对象都有一个方法和方法,其中方法返回一个表示该对象的字符串,方法返回该对象的原始值。这两个方法都是原型链上的方法,被每个对象所继承。

valueOf()方法和toString()方法介绍

valueOf()方法和toString()

我们知道在js中,"一切皆为对象"。每个对象都有一个toString()方法和value方法,其中toString()方法返回一个表示该对象的字符串,value方法返回该对象的原始值。对于toString方法来说,当对象被表示为文本值或者当以期望字符串的方式引用对象时。该方法被自动调用。对于一个对象,toSting()返回"[object type]",其中type是对象类型。如果x不是对象,toString()返回应有的文本值。
对于valueOf() 方法来说,默认情况下, valueOf() 会被每个对象Object继承。每一个内置对象都会覆盖这个方法为了返回一个合理的值,如果对象没有原始值,valueOf() 就会返回对象自身。
但是注意,对于Null如果
不同类型的对象的value方法的返回值

对象 返回值
Array 返回数组对象本身
Boolean 布尔值
Date 返回的时间是从1970年1月1日午夜开始计的毫秒数UTC
Function 函数本身
Number 数字值
Object 对象本身。这是默认情况
String 字符串值
Math和Error对象没有valueOf方法

二者的使用场景以及区别与比较

通过来自MDN[!https://developer.mozilla.org...]上面对两个方法的介绍,我们得知。这两个方法都是Object原型链上的方法,被每个对象所继承。下面,我们看下该方法在两个应用场景下的区别。
1、对于值类型数据(又叫基本类型)场景下,toString及valueOf方法的使用

var str = "hello",n = 123,bool = true;

console.log(typeof(str.toString())+ "_"+ str.toString())        //string_hello
console.log(typeof(n.toString())+"_"+n.toString()  )            //string_123
console.log(typeof(bool.toString())+"_"+bool.toString())        //string_true

toString放对于值类型数据使用而言,其效果相当于类型转换,将原类型转为字符串。

console.log(typeof(str.valueOf())+"_"+str.valueOf())            //string_hello
console.log(typeof(n.valueOf())+"_"+n.valueOf())                //string_123
console.log(typeof(bool.valueOf())+"_"+bool.valueOf())          //string_true

console.log(str.valueOf === str) //  // true
console.log(n.valueOf === n) //   // true
console.log(bool.valueOf() === bool) // true

由上面的例子可以得出,
toString方法对于值类型数据使用而言,其效果相当于类型转换,将原类型转为字符串。
valueOf方法对于值类型数据使用而言,其效果将相当于返回原数据。
2、复合对象类型数据使用toString及valueOf方法

var obj = {};

console.log(obj.toString());    //[object Object] 返回对象类型
console.log(obj.valueOf());     //{} 返回对象本身

可以看到与方法介绍中所说一致。下面让我们看下,具体两个方法是如何执行的。

var test = { 
 i: 10, 
 toString: function() { 
 console.log("toString"); 
 return this.i; 
 }, 
 valueOf: function() { 
 console.log("valueOf"); 
 return this.i; 
 } 
} 
alert(test);// 10 toString 
alert(+test); // 10 valueOf 
alert(""+test); // 10 valueOf 
alert(String(test)); // 10 toString 
alert(Number(test)); // 10 valueOf 
alert(test == "10"); // true valueOf 
alert(test === "10"); // false

其中,第一个alert,我们可以看到调用了toString方法,说明alert这里是需要一个字符串,这样我们可以推测,toString()方法一般不需要我们主动去显示的调用,符合对象类型会在相应的场景中调用适合的方法,返回适当类型的值。
第二个,这里通过alert我们知道这里依然是需要一个字符串的值,所以这里是+test调用了toString方法。而对于test,调用valueOf方法。在有运算操作符的情况下,valueOf的优先级要高一点。可以看一个例子。

var ab = { 
  i: 1, 
  valueOf: function () { 
    alert("你调用了a的valueOf函数"); 
    return this.i; 
  }, 
  toString: function () { 
    alert("你调用了a的toString函数"); 
    return this.i; 
  } 
}; 
var c = { 
  i: +ab, 
  valueOf: function () { 
    alert("你调用了c的valueOf函数"); 
    return this.i; 
  }, 
  toString: function () { 
    alert("你调用了c的toString函数"); 
    return this.i; 
  } 
}; 
alert(c);

第三个,同样我们可以把上面的例子改为。

var c = { 
  i: ""+ab, 
  valueOf: function () { 
    alert("你调用了c的valueOf函数"); 
    return this.i; 
  }, 
  toString: function () { 
    alert("你调用了c的toString函数"); 
    return this.i; 
  } 
}; 
alert(c);

第四个,String方法是要返回一个字符串类型,所以这里调用了toString()方法。
第五个,强转换为数字类型,调用了valueOf方法。
第六个,这个里面的判等的顺序是,获取原始值,然后判断两边的原始值是否相等,所以调用valueOf。
第七个,alert(bbb === "10"); // false
===操作符不进行隐式转换,判全等的第一个步骤是判断类型,因为类型都不一样了,所以后面什么都不会调用.
总结:
1、在进行强转字符串类型时将优先调用toString方法,强转为数字时优先调用valueOf。
2、在有运算操作符的情况下,valueOf的优先级高于toString。
这两个方法一般是交由js去隐式调用,以满足不同的运算情况。
在数值运算里,会优先调用valueOf(),如 a + b;
在字符串运算里,会优先调用toString(),如alert(c).

补充下toString()方法和String()方法的区别

toString()方法和String()方法都可以转换为字符串类型。
1、toString()可以将所有的数据都转换为字符串,但是要排除null和undefined

var str = false.toString();
console.log(str, typeof str);         //false, string

但是 null和undefined不能转换为字符串,null和undefined调用toString()方法会报错

var str = null.toString();
var str = undefined.soString();

如果当前数据为数字类型,则toString()括号中的可以写一个数字,代表进制,可以将数字转化为对应进制字符串。

var num = 123;
console.log(num.toString()+"_"+ typeof(num.toString()));    //123_string
console.log(num.toString(2)+"_"+typeof(num.toString()));    //1111011_string
console.log(num.toString(8)+"_"+typeof(num.toString()));    //173_string
console.log(num.toString(16)+"_"+typeof(num.toString()));   //7b_string

2、String()可以将null和undefined转换为字符串,但是没法转进制字符串。当 String() 和运算符 new 一起作为构造函数使用时,它返回一个新创建的 String 对象,存放的是字符串 s 或 s 的字符串表示。

var str = new String("123");
console.log(str+"_"+typeof(str));     //123_object

当不用 new 运算符调用 String() 时,它只是把s转换成原始的字符串,并返回转换后的值。

var str = String(s);
console.log(str+"_"+typeof(str))                      //123_string
Symbol.toPrimitive

对象的Symbol.toPrimitive属性。指向一个方法。该对象被转化为原始类型的值时,会调用这个办法,返回该对象对应的原始类型值。
Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一个有三种模式。

Number:该场合需要转成数值

String:该场合需要转成字符串

Default:该场合可以转成数值,也可以转成字符串。

以上内容来自阮老师的ES6入门,下面我们结合几个例子,具体看下Symbol.toPrimitive是如何被调用的。

// 没有 Symbol.toPrimitive 属性的对象
var obj1 = {};
console.log(+obj1);       //NaN
console.log(`${obj1}`);   //"[object Object]"
console.log(obj1 + "");   //"[object Object]"

上面的结果我们可以通过上面说的toSting()方法和value方法去理解。
第一个,+符号。可以看成是是把数据转化为数字类型,由于obj是个空对象,所以结果是NaN
第二个,是es6中的字符串的新语法,这里需要的结果是一个字符串,所以使用的是toString()方法,而toString()方法返回的是对象的类型。
第三个,这里是连接符连接obj。实际上也是需要字符串的结果,所以同理。

// 拥有 Symbol.toPrimitive 属性的对象
var obj2 = {
  [Symbol.toPrimitive](hint) {
    if(hint == "number"){
        return 10;
    }
    if(hint == "string"){
        return "hello";
    }
    return true;
  }
}

console.log(+obj2);     //10    --hint in "number"
console.log(`${obj2}`); //hello --hint is "string"
console.log(obj2 + ""); //"true"
// 拥有 Symbol.toPrimitive 属性的对象
let obj = {
  [Symbol.toPrimitive](hint) {
    if(hint === "number"){
      console.log("Number场景");
      return 123;
    }
    if(hint === "string"){
      console.log("String场景");
      return "str";
    }
    if(hint === "default"){
      console.log("Default 场景");
      return "default";
    }
  }
}
console.log(2*obj); // Number场景 246
console.log(3+obj); // String场景 3default
console.log(obj + "");  // Default场景 default
console.log(String(obj)); //String场景 str

由以上例子可以总结,一般情况下,+连接运算符传入的参数是default,而对于乘法等算数运算符传入的是number。对于String(str),${str}等情况,传入的参数是defalut。

Symbol.toPrimitive和toString、valueOf

当然,你也可以重写一个不做参数判断的Symbol.toPrimitive方法,结合上面提到的toString,可以有以下例子。

let ab = {
    valueOf() {
        return 0;
    },
    toString() {
        return "1";
    },
    [Symbol.toPrimitive]() {
        return 2;
    }
}
console.log(1+ab);
console.log("1"+ab);

可以看到,Symbol.toPrimitive方法在转换基本类型的时候优先级最高。

参考链接:
http://www.sohu.com/a/1464105...
https://www.cnblogs.com/good1...
https://www.jb51.net/article/...
https://yuchengkai.cn/docs/zh...
https://github.com/ruanyf/es6...
https://developer.mozilla.org...
https://blog.csdn.net/kittyji...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97524.html

相关文章

  • ECMAScript7规范中ToPrimitive抽象操作

    摘要:本文将介绍规范中的抽象操作。它们主要用于规范的说明,不需要被真正地实现。该抽象操作接受一个参数和一个可选的参数。根据规范中的加法操作,对于操作,会调用和把和转化为原始数据类型。 本文将介绍ECMAScript7规范中的ToPrimitive抽象操作。 预备知识 ECMAScript数据类型 ECMAScript数据类型细分为两大类数据类型,一种是语言类型,一种是规范类型: 语言类型...

    张汉庆 评论0 收藏0
  • 有关javascript强制转换不得不说故事

    摘要:我们首先了解一下中有关类型转换的知识。新增类型抛出异常从列表可以明显看到少了一个类型转换为的规则。这里要强调一点第二个表达式没有涉及到强制类型转换。如果文中有错误或者有某些强制转换的情形没有涉及到请及时留言告知,我会修改并补充进去。 javascript是一门非常奇特的语言,它有时候奇特的会让人怀疑人生。比如让我们看一下下面的一些奇葩例子: false == 0 ...

    xcold 评论0 收藏0
  • JavaScript 实现a 可以同时 == 1 && == 2 &&

    摘要:先测试得到以下结果可看到正则进行全局搜索判断返回一个数据数组的首元素为成功匹配的文本因此每次进行时都会返回数组的首元素也就是匹配的文本由此实现这个功能参考自微信公众号鱼头的海洋 参考自 微信公众号 鱼头的Web海洋 关于这道题目: var a = ?; if (a == 1 && b == 2 && c == 3) { console.log(yes); } 学习了网上的几种解...

    khs1994 评论0 收藏0
  • 魔幻语言 JavaScript 系列之类型转换、宽松相等以及原始值

    摘要:通过使用其构造函数,可以将一个值的类型转换为另一种类型。如果使用两次,可用于将该值转换为相应的布尔值。 编译自:[1] + [2] – [3] === 9!? Looking into assembly code of coercion.全文从两个题目来介绍类型转换、宽松相等以及原始值的概念: [1] + [2] – [3] === 9 如果让 a == true && a == fa...

    li21 评论0 收藏0
  • JavaScript 运算符规则与隐式类型转换详解

    摘要:我们再来回顾下文首提出的这个比较运算,首先为对象,则调用函数将其转化为字符串对于右侧的,首先会进行显式类型转换,将其转化为。 JavaScript 运算符规则与隐式类型转换详解 从属于笔者的现代 JavaScript 开发:语法基础与工程实践系列文章,主要探讨 JavaScript 中令人迷惑的加减乘除与比较等常见运算中的规则与隐式类型转换;本文中涉及的参考资料全部声明在了JavaSc...

    snifes 评论0 收藏0

发表评论

0条评论

el09xccxy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<