JavaScript系列-----Object之toString()和valueOf()方法 (2)

深入理解toString()和valueOf()函数


1.我们为什么要了解这两种方法

    众所周知,toString()函数和valueOf函数,这两个函数是Object类的对象生来就拥有的,而且他们还可以允许我们重写,那么,这两个函数到底有什么用呢?

 从名称上判断,toString()将对象转换为字符串,valueOf将对象转化为值.那么问题来了:什么时候需要将对象转换为值,又什么时候需要将对象转换为字符串呢?------这是我们这篇文章的核心。

   在谈这个问题之前,我们先看一道题目:       

   这是一道很经典的题目,考察的就是我们对于一些基本概念的理解,当然也是一道很难的题目,甚至第一眼看起来是一道不可能实现的题目.

 请用javascript语言实现,  var a= add(1)(2)(3)(4)(5); //结果为5个数相加,15------------来源于http://dmitry.baranovskiy.com/post/31797647 

 

var add = function (n) {
  var result = n;
  var func1 = function (m) {
    result += m;
    return func1;
  }
  func1.toString = function () {
    return result.toString();
  }//重写对象的toStrig函数
  func1.valueOf = function () {
    return result;
  }//重写对象的valueOf函数
  
  return func1;
}
var a = add(1)(2)(3)(4)(5);
console.log(a);//15
console.log(a+10)//25
答案

 

..上面的这道题目不是那么容易想到,而且一般来说,程序员也不会写这种自己看着都别扭的代码..我们只是以此来引申出一些最基本的概念,也是这篇文章存在的必要性。

从上面的举例中,我们可以看出: 在输出的时候,伴随着Function类型向String类型之间的转换。那么,这种转换是怎么发生的呢? 在第二部分,会给出令您满意的解释!

 

 现在我们先需要知道一点: toString和valueOf这两个函数,是解释器用来帮我们自动完成类型之间的转换(一般是对象到基本类型的转换),进而输出令我们满意的结果。

 


2. 对象向基本数据类型的转换的规则

 (1)vauleOf优先于toString()被调用的情况---------当对象作为操作数的时候(Date类型的除外)

先来看看下面操作运算时,数据类型的转换

 1 var x="10";
 2 
 3 var a=+x;
 4 console.log(typeof a);     //number
 5 
 6 
 7 var b=a+x;
 8 console.log(typeof b);    //string

上面只是我列举出的三种比较常见的类型转换,也是一些最基本的概念...下面花一点时间来解析这三种类型转换是怎么发生的

3-4行:  "+"号作为一元运算符---- 在这个运算符下,对象向基本数据类型的转换规则:

              (1).当操作数是基本数据类型的时候,调用Number()函数,将其转换为数值

                (2). 当操作数是对象的时候,调用对象的toString或者valueOf函数,将对象转化为基本数据类型的值,然后再对该值调用Number()函数。

 

 所以,根据以上的转换规则,上述的输出结果为 number 也就合理了.

 但是,第二条转换规则里,蕴含了一个好大的坑啊:到底是调用toString()还是valueOf(),要是两个函数都能将对象转换为基本数据类型呢(比如Date类型的对象),你又调用谁呢?

  类似下面这样:

var x = {
  toString: function () {
    return '0';
  },
  valueOf: function () {
    return 1;
  }
}
var a = + x;  //在这一步,到底调用的是toString()还是valueOf()呢?,在 + 号作为二元运算符的部分,会给出解释
console.log(a);
 1
输出结果

 

7-8行:“+”号作为二元运算符 ----- 在这个运算符下,对象向基本数据类型的转换规则

   当“+”号作为2元运算符的时候情况就比较复杂了,因为"+"号可以当做字符串的连接,也可以当做数字的相加减。你可以查下转换规则,怎么也有个7,8条,看的人眼花撩换。我经过大量的测试,也查阅了一些的资料,总结出以下规律:

//伪代码,
a + b运算转换规则:

var Pa = toPrimitive(a);
var pb = toPrimitive(b);
 try {
  if ((Pa is String) || (Pb is String)) {
      return contact(String(Pa), String(Pb));
     } else {
      return Number(Pa) + Number(Pb);
     }
    } catch (e) {
      throw e;
  }

 //注: toPrimitive 是将操作数转化为基本数据类型,优先调用valueOf,若得到基本数据类型,则结束,否则继续掉用toString()。(也就是说valueOf的优先级高于toString())

  熟知了这些,也就可以看出,+号作为一元运算符转换规则其实和其作为二元运算符差不多,转化为基本数据类型的时候总是优先调用valueOf()。下面来一个例子来验证:

 1 var test = {
 2   valueOf: function () {
 3     return 1;
 4   },
 5   toString: function () {
 6     return '0';
 7   }
 8 }
 9 console.log( + test);   //1
10 var result = test + test;
11 console.log(result);  //2

 谈完了上面这些,我们可以总结得出结论: 在操作数运算的时候(无论是一元的还是二元的运算),数据类型之间的转换总是优先调用valueOf()函数,但是“+”号在作为二元运算符时,这种优先顺序在应用于Date类型的对象时,被逆转了(toString的优先级较高)

   谨记:Date类型是一个特例,当且仅当在+号运算,且“+”号作为二元运算符时,toString()优先调用,比如下面这样,

var date=new Date();

console.log(+date);  //仍然优先调用valueOf  
console.log(date+"toString优先被调用");
 
//输出结果:
// 1421293488713
//Thu Jan 15 2015 11:44:48 GMT+0800toString优先被调用

 

(2):toString()优先于valueOf()被调用 的情况------当你想要输出结果是字符串的时候  

当访问Object类型对象的变量,我们用[] 这种方括号访问的时候,方括号的内容总是优先转化为字符串,也就是优先调用 toString()函数。看下面这个例子:

 1 var test = {
 2   toString: function () {
 3     return '0'
 4   },
 5   valueOf: function () {
 6     return 1;
 7   }
 8 };
 9 
10 var object={};
11 object[test]=1000;
12 console.log(object);  // 输出结果:Object { 0=1000}

此时调用的原则描述如下:

[a]以这种形式访问的时候:
var Pa=toPrimitive(a);
if(Pa is prmitive){
    var str=String(Pa);
    }else{
throw error;//cannot convert to string
    }
[str]//str为字符串的形式
   //注: toPrimitive()此时优先调用toString()函数,若结果为基本类型,返回,否则继续调用valueOf();
 

 

还有几种toString优先于valueOf()被调用的例子 
var test = {
  toString: function () {
    return '0'
  },
  valueOf: function () {
    return 1;
  }
};

alert(test); //优先调用toString() 输出 0
对象直接输出,优先调用toString()
var test = {
  toString: function () {
    return '0'
  },
  valueOf: function () {
    return 1;
  }
};
var test1 = {
  toString: function () {
    return '0'
  },
  valueOf: function () {
    return 1;
  }
}
var array = [
  test,
  test1
];
console.log(array + '')


//我们分析一下输出的过程:

 //1.array+" "执行操作的时候,优先调用array.valueOf()函数,发现不能输出基本类型的值
 //2.然后调用array.toString()函数。这个函数被Array类重写了,重写后,对于每一个数组元素
   //优先调用toString()函数,然后再调用valueOf()函数。(这是重写后的自定义的规则,并不是默认的)
二,数组转化为字符串优先选择toString

 3.为什么会出现这些奇怪的现象

    由上面可以看出,toString和valueOf这两个函数在转换的时候都是可能被调用的,只是在不同的环境下,调用的优先级不一样而已。这些对于我们程序员来说,可能是透明的,但是对于解释器说,它们干的活可就多了...一句话归结:解释器总是根据语境尽可能的转化为我们想要的结果。换句话说:

 

 对象在作为操作数时,解释器总是优先调用valueOf()--(Date类型的对象在二元“+”运算时例外),而其他情况,解释器总是认为我们想要的是字符串,所以会优先调用toString()。

 注:Date类型的对象之所以会在二元+运算时优先调用toString(),也是因为我们大多数情况下, 时间总是和字符串连接使用,而时间和一个数字相加的情况好少,所以Date类型中,toString()优先级才比较        高。

 

 正是因为解释器总想完美的输出我们想要的结果,才会造成这种杂乱的现象和规则出现。天下间本没有完美的事物,矛和盾总是相依相存。

 懂得规则,才能利用规则,回过头来看一下我们在最开始所出的题目吧。是不是就是对这些规则的合理利用呢。

 

 

 

                    题外话: 写这篇文章就是为了表明基础知识的重要性,并非追求一个稀奇古怪的程序,程序员追求的应该是通俗易懂的代码(大道至简)而不是这些看起来四不像的程序,切记本末倒置!

                                  另外,看完了这些是不是有一种回头重新看书的冲动呀,如果有,那我的目的就达到了...哈哈!

备注: toLocaleString()这个函数是实现字符串的本地化的输出,一般和toString()输出的结果相同,没什么特殊的,就是一个普通的函数。在Date类型中,这个函数被重写了。

              

转载于:https://www.cnblogs.com/renlong0602/p/4223852.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 中,Valueof、toString、toLocaleString 都是 Object 原型链上的方法,可以用来获取对象的值或者转换为不同的字符串形式。 1. valueOf(): valueOf() 方法返回一个对象的原始值。当 JavaScript 需要一个对象的原始值时,它会自动调用 valueOf() 方法。如果没有找到原始值,则会尝试调用 toString() 方法。 例如: ```javascript let num = new Number(10); console.log(num.valueOf()); // 10 ``` 这里的 `valueOf()` 返回了 `num` 的原始值,即 `10`。 2. toString(): toString() 方法返回一个对象字符串表示形式。当 JavaScript 需要将一个对象转换字符串时,它会自动调用 toString() 方法。 例如: ```javascript let num = new Number(10); console.log(num.toString()); // "10" ``` 这里的 `toString()` 返回了 `num` 的字符串表示形式,即 `"10"`。 3. toLocaleString(): toLocaleString() 方法返回一个对象的本地化字符串表示形式。当 JavaScript 需要将一个对象转换为本地化字符串时,它会自动调用 toLocaleString() 方法。该方法返回的字符串与所在地区的语言和文化相关。 例如: ```javascript let num = new Number(1234567.89); console.log(num.toLocaleString()); // "1,234,567.89" ``` 这里的 `toLocaleString()` 返回了 `num` 的本地化字符串表示形式,即 `"1,234,567.89"`,与所在地区的语言和文化相关。 总之,这三个方法都是用来获取对象的值或者转换为不同的字符串形式,但是具体使用要看实际情况和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值