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

必读:

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

Javascript对象Oject的强制类型转换

JavaScript筑基篇(二)->JavaScript数据类型

聊一聊valueOf和toString

深入理解JavaScript系列(12):变量对象(Variable Object)

JS的数据类型

  • 基本数据类型(其实也统称为基本型或原始型):undefined,null,number,boolean,string——按值访问

  • 一种复杂数据类型(引用型):Object——按址访问

数据类型介绍

undefined 类型:声明未定义

null 类型:null值表示一个空指针,初始化空对象可赋值为null

boolean 类型:注意true不一定等于1,而false也不一定等于0

要将一个值转为boolean型等价的值,有两种方案:

  • 一种是显式转换-调用类型转换函数Boolean()

  • 一种是自动转换-如if(value)中的value就会自动转化成为boolean值

各类型与boolean型之间值得转换关系:

数据类型 转换为true的值 转换为false的值
boolean true false
string 任何非空字符串 "" (空字符串)
bumber 任何非零数字值(包括无穷大) 0和NaN
undefined undefined
null null
Object 任何对象

 

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()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再依次按照前面的规则转换返回的字符串值。

console.log(Number('')) //0
console.log(Number('a')) //NaN
console.log(Number(true)) //1
console.log(Number('001')) //1
console.log(Number('001.1')) //1.1
console.log(Number('0xf')) //15
console.log(Number('000xf')) //NaN

var a = {} // 调用对象的valueOf()方法
console.log(Number(a)) //NaN
a.toString = function () {
  return 2
}

// 重写valueOf()方法
console.log(Number(a)) //2
a.valueOf = function () {
  return 1
}
console.log(Number(a)) //1

 

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

 

string字符串:

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

  • 第一种是使用几乎每个值都有的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(获得该值的字符串表示法) 执行了

 

object类型:

Object的每个实例都具有下列属性和方法:

  • constructor——保存着用于创建当前对象的函数

  • hasOwnProperty(propertyName)——用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:o.hasOwnProperty("name")

  • isPrototypeOf(object)——用于检查传入的对象是否是另一个对象的原型

  • propertyIsEnumerable(propertyName)——用于检查给定的属性是否能够使用for-in语句来枚举

  • toString()——返回对象的字符串表示

  • valueOf()——返回对象的字符串、数值或布尔值表示。

var obj = new Object();
obj.name = 'zs';
obj.sayHi = function () {
  console.log('Hi');
}
console.log(obj.hasOwnProperty('a')); // 实例对象 true
console.log(obj.hasOwnProperty('sayHi')); // 实例对象 true
console.log(obj); // 实例对象
console.log(obj.constructor); // 构造函数Object()
console.log(obj.__proto__); // 原型

 

valueOf()toString()

  • valueOf方法返回指定对象的原始值。

  • toString: 返回对象的字符串表示

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

 

对象转换为布尔值

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

// 保存原始的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 = {};
var b = new Boolean(false);

if (a) {
  console.log(1);
}
if (b) {
  console.log(2);
}

 

对象转换为数字

对象转换为数字会依次调用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]",对象最终转换为该字符串

 

// 保存原始的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 this;
};
var a = {};
alert(a); 
/*
toString
valueOf
Uncaught TypeError: Cannot convert object to primitive value
    at 1.js:16
*/

 

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 "字符串"

 

强制类型转换

Number强制转换对象

let a = { name: 123 };
console.log(Number(a)); // NaN
/*
* JS对象强制类型转换
* 主要调用 object.valueOf() 和 object.toString() 方法
* 1.先调用 object 的 valueOf() 方法
* 2.判断返回值 是否为 基础数据类型?
* 3.是!则转换规则按照相应数据类型的规则对其进行转换
* 4.不是!在返回值的基础上继续调用 toString() 方法
* 5.判断调用 toString() 方法返回值是否为 基础数据类型
* 6.是!则转换规则按照相应数据类型的规则对其进行转换
* 7.不是!报错:
* */

 

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

 现在我们用自定义方法覆盖toString()方法:

a.toString = function () {return {name: 'newName'}} // 让toString方法返回值为 复杂数据类型
a.toString() // 调用覆盖的方法
Number(a) // 报错

JS高级学习笔记(1)- 数据类型及转换规则_第2张图片

 现在验证让toString()方法返回值为 基础数据类型

a.toString = function () {return '321'} // 让toString方法返回值为 复杂数据类型
a.toString() // 调用覆盖的方法
Number(a) // 321

JS高级学习笔记(1)- 数据类型及转换规则_第3张图片

所以Number强制转换对象的过程即为如上7步

对象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]

 

JS高级学习笔记(1)- 数据类型及转换规则_第4张图片

 

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({}); // {}
console.log(Number({})); // NaN、
console.log(String({})); // [object Object]
console.log(Boolean({})); // true

console.log([]); // []
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([] + []) // 空字符串

 

你可能感兴趣的:(JS高级学习笔记(1)- 数据类型及转换规则)