JS高级学习笔记(1)-数据类型及转换规则

必读:

深入理解Javascript中的valueOf与toString

JavaScript类型系统之基本数据类型与包装类型

toString()

toString() 作用是返回 object 的字符串表示,JavaScript中object默认的toString()方法返回字符串”[object Object]“。

注意,基本数据类的 toString() 方法,是由基本包装类型提供。
对象toString返回值
Array 以逗号分割的字符串,如[1,2]的toString返回值为"1,2",跳过null,undefined
Boolean "True"
Date 可读的时间字符串,如"Tue Oct 15 2019 12:20:56 GMT+0800 (中国标准时间)"
Function 声明函数的JS源代码字符串
Number "数字值"
Object "[object Object]"
String "字符串"

valueOf()

valueOf()函数的作用是返回该object自身。与toString()一样,定义类时可以实现新的valueOf()方法,覆盖原生的 valueOf() 方法。

MDN对valueOf()的描述:

JavaScript调用valueOf方法将对象转换为原始值。你很少需要自己调用valueOf方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。

默认情况下,valueOf方法由 Object 后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf将返回对象本身。

JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同。
对象valueOf返回值
Array 数组本身
Boolean 布尔值
Date 返回毫秒形式的时间戳
Function 函数本身
Number 数字值
Object 对象本身
String 字符串值
// Array:返回数组对象本身
var array = ["ABC", true, 12, -5];
console.log(array.valueOf() === array);   // true

// Date:当前时间距1970年1月1日午夜的毫秒数
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
console.log(date.valueOf());   // 1376838719230

// Number:返回数字值
var num =  15.26540;
console.log(num.valueOf());   // 15.2654

// 布尔:返回布尔值true或false
var bool = true;
console.log(bool.valueOf() === bool);   // true

// new一个Boolean对象
var newBool = new Boolean(true);
// valueOf()返回的是true,两者的值相等
console.log(newBool.valueOf() == newBool);   // true
// 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型
console.log(newBool.valueOf() === newBool);   // false

// Function:返回函数本身
function foo(){}
console.log( foo.valueOf() === foo );   // true
var foo2 =  new Function("x", "y", "return x + y;");
console.log( foo2.valueOf() );
/*
ƒ anonymous(x,y) {return x + y;}
*/

// Object:返回对象本身
var obj = {name: "张三", age: 18};
console.log( obj.valueOf() === obj );   // true

// String:返回字符串值
var str = "http://www.xyz.com";
console.log( str.valueOf() === str );   // true

// new一个字符串对象
var str2 = new String("http://www.xyz.com");
// 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型
console.log( str2.valueOf() === str2 );   // false

对象转换为布尔值

直接转换为true(包装类型也一样),不调用valueOf和toString

对象转换为数字

对象转换为数字会依次调用valueOf和toString方法,具体规则如下:

  1. 如果对象具有valueOf方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字

  2. 如果对象具有toString方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字

  3. 转换失败,抛出TypeError

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this);
};
var a = {};
console.log(++a); // valueOf toString NaN
  1. valueOf方法返回的是对象本身,不是原始值,继续执行

  2. toString方法返回的是"[object Object]",是原始值(字符串),将字符串转换为数字NaN

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return "1"; // 强制返回原始值
};
// 添加toString日志
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this);
};
var a = {};
console.log(++a); // valueOf 2

分析:valueOf返回原始值(字符串),直接将该字符串转换为数字,得到1

对象转换为字符串

对象转换为数字会依次调用toStringvalueOf方法,具体规则如下:

  1. 如果对象具有toString方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串

  2. 如果对象具有valueOf方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串

  3. 转换失败,抛出TypeError

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日志
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日志
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this); // '[object Object]'  toString方法先调用 ,如果返回结果是字符串,则停止调用 valueOf,不是字符串,那么就调用 valueOf
};
var a = {};
console.log(a.toString()); // valueOf toString [object Object]str
// alert(a) // alert主动调用toString方法,返回了字符串"[object Object]",对象最终转换为该字符串

  

加强记忆

demo1:

var colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组 
console.log('原数组:', colors); // ["red", "blue", "green"]
// valueOf 返回本身
console.log(colors.valueOf()); // ["red", "blue", "green"]
// toString 返回字符串
console.log(colors.toString()); // red,blue,green 

colors.valueOf = function () {
    return '改写了Array的valueOf'
}
colors.toString = function () {
  return '改写了Array的toString'
}
console.log(colors.valueOf()); // 改写了Array的valueOf
console.log(colors.toString()); // 改写了Array的toString

demo2:

var colors = {
  name: 'red'
};
colors.valueOf = function () {
  console.log('改写了colors的valueOf')
  return []
}
colors.toString = function () {
  console.log('改写了colors的toString')
  return 2
}
console.log(Number(colors));
/*
改写了colors的valueOf
改写了colors的toString
2
*/
 
1. valueOf 方法返回的是 简单数据类型,那么就用返回的 简单数据类型 调用Number() 方法
2. valueOf 方法返回的是 复杂数据类型,那么就去调用 toString 的方法,然后判断 toString 方法的返回值,再根据这个返回值调用Number() 方法

number相关

将非number类型的值转换为number类型

  • 一种是隐式转换,如进行(*、/)操作时,会自动其余类型的值转为number类型

  • 一种是显示转换-调用Number()、parseInt()、parseFloat()方法转换 

Number():

  • 如果是boolean值,true和false将分别被替换为1和0

  • 如果是数字值,只是简单的传入和返回

  • 如果是null值,返回0

  • 如果是undefined,返回NaN

  • 如果是字符串,遵循下列规则:

    • 如果字符串中只包含数字,则将其转换为十进制数值,即”1“会变成1,”123“会变成123,而”011“会变成11(前导的0被忽略)

    • 如果字符串中包含有效的浮点格式,如”1.1“,则将其转换为对应的浮点数(同样,也会忽略前导0)

    • 如果字符串中包含有效的十六进制格式,例如”0xf“,则将其转换为相同大小的十进制整数值

    • 如果字符串是空的,则将其转换为0

    • 如果字符串中包含除了上述格式之外的字符,则将其转换为NaN

  • 如果是对象,则调用对象的valueOf()方法,再调用对象的toString()方法,然后再依次按照前面的规则转换返回的字符串值。

parseInt():

常常用于将其它类型值转化为整形。parseInt转换与Number()有区别,具体规则如下:

  • parseInt(value,radius)有两个参数,第一个参数是需要转换的值,第二个参数是转换进制(该值介于 2 ~ 36 之间。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。),如果不传(或值为0),默认以10为基数(如果value以 “0x” 或 “0X” 开头,将以 16 为基数)

  • 注意在第二个参数默认的情况下,如果需要转换的string值以0开头,如'070',有一些环境中,会自动转化为8进制56,有一些环境中会自动转化为10进制70。所以为了统一效果,我们在转换为10进制时,会将第二个参数传10

console.log(parseInt('')) //NaN
console.log(parseInt('a')) //NaN
console.log(parseInt('1234blue')) //1234
console.log(parseInt(true)) //NaN
console.log(parseInt('070')) //70,但是有一些环境中会自动转换为8进制56
console.log(parseInt('070', 8)) //56
console.log(parseInt('001.1')) //1
console.log(parseInt('0xf')) //15,16进制
console.log(parseInt('AF', 16)) //175,16进制
console.log(parseInt('AF')) //NaN
console.log(parseInt('000xf')) //0

var a = {}
console.log(parseInt(a)) //NaN
a.toString = function () {
  return 2
} // 重写valueOf()方法
console.log(parseInt(a)) //2
a.valueOf = function () {
  return 1
} // 重写valueOf()方法
console.log(parseInt(a)) //2

parseFloat():

parseFloat()转换规则基本与parseInt()一致,只有如下不同点

  • parseFloat()遇到浮动数据时,浮点有效(但是只有第一个.有效),如"10.1"会被转为10.1;'10.1.1'会被转为10.1

  • parseFloat()只会默认处理为10进制,而且会忽略字符串前面的0,所以不会有在默认情况下转为8进制的情

console.log(parseFloat('1234blue')) //1234
console.log(parseFloat('1234blue', 2)) //1234
console.log(parseFloat('0xA')) //0
console.log(parseFloat('10.1')) //10.1
console.log(parseFloat('10.1.1')) //10.1
console.log(parseFloat('010')) //10

由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是parseInt()函数-需注意最好第二个参数传10,处理浮点数时更常用parseFloat()

另外注意,浮点数直接的计算存在误差,所以两个浮点数无法用"="进行判断

var a = 10.2
var b = 10.1
console.log(a - b === 0.1) //false
console.log(a - 10.1 === 0.1) //false,实际是0.09999999999999964
console.log(a - 0.1 === 10.1) //true

 

字符串

要把一个值转换为一个字符串有三种方式。

  • 第一种是使用几乎每个值都有的toString(基数)方法(除去null和undefined没有)——当需要toString的值为number时,参数可以生效。

  • 第二种是隐式转换,+ 号:要转换的值为对象时,回调用对象的valueOf属性。

  • 第三种是通过转换函数String(),转换规则如下

    • 如果值有toString()方法,则调用该方法(没有参数)并返回相应的结果,(注意不会调用valueOf()方法)

    • 如果值是null,则返回null,如果值是undefined,则返回undefined

var c = {};
console.log(c);//[object Object]
console.log(c + '1');//[object Object]1
console.log(String(c));//[object Object]

c.valueOf = function () { return '重写c的valueOf方法' };
console.log(c);// {valueOf: ƒ}   valueOf重写
console.log(c + '1');// 重写c的valueOf方法1    隐式转换时,valueOf起作用了

console.log(String(c));// [object Object]
c.toString = function () { return '重写c的toString方法' };
console.log(c);// {valueOf: ƒ, toString: ƒ}  toString起作用了
console.log(String(c)); // 重写c的toString方法

console.log(String(null));// null,null和undefined可以String()输出
console.log(String(undefined));// undefined ,null和undefined可以String()输出
// console.log(null.toString());//报错,null和undefined不能toString

let d = {}
d.valueOf = function () {
  console.log('valueOf 执行了')
  return 'valueOf'
};
d.toString = function () {
  console.log('toString 执行了')
  return 'toString'
};
console.log(d + '1') // 隐式转换 valueOf(转换为原始值) 执行了
console.log(String(d)) // String toString(获得该值的字符串表示法) 执行了

对象String()转换字符串

/* 1.先调用对象的toString方法
2.判断该方法的返回值是否为基础数据类型(Number,String,Boolean,Undefined,ull)
3.若返回值为基础数据类型,则转换规则按照相应数据类型的转换规则对其进行转换
4.若返回值不为基础数据类型,则在该返回值的基础上继续调用valueOf方法
5.判断valueOf的返回值是否为基础数据类型
6.判断是否为基础数据类型,若是基础数据类型则进行操作3
7.若仍旧不为基础数据类型则报错 */

let b = {name: 'houfee'}
console.log(String(b)); // [object Object]
let c = []
console.log(String(c)); // 空字符串
let d = {}
console.log(String(d)); // [object Object]

String与Number的区别则在于

  • Number是先调用valueOf()再调用toString ()

  • 而String是先调用toString()再调用valueOf()

Number()先转换为原始类型,再转化为字符串形式

String()先转换为字符串形式,再转化为原始类型

 

判断数据类型

function isArray(value) {
  return Object.prototype.toString.call(value) == "[object Array]"
}
function isFunction(value) {
  return Object.prototype.toString.call(value) == "[object Function]"
}
function isRegExp(value) {
  return Object.prototype.toString.call(value) == "[object RegExp]"
}

面试题

console.log(Number({})); // NaN、
console.log(String({})); // [object Object]
console.log(Boolean({})); // true

console.log(Number([])); // 0
console.log(String([])); // 空字符串
console.log(Boolean([])); // true

console.log({} + {}) // [object Object][object Object]
console.log({} + []) // [object Object]
console.log([] + {}) // [object Object]
console.log([] + []) // 空字符串
原文地址:https://www.cnblogs.com/houfee/p/10393843.html