JS高级学习笔记(1)- 基本数据类型 和 强制类型转换
必读:
JavaScript筑基篇(二)->JavaScript数据类型
深入理解JavaScript系列(12):变量对象(Variable Object)
-
基本数据类型(其实也统称为基本型或原始型)
undefined,null,number,boolean,string
-
一种复杂数据类型(引用型)
Object
1.1数据类型介绍
undefined 类型:声明未定义
let a a === undefined // true
null 类型:null值表示一个空指针,初始化空对象可赋值为null
console.log(undefined == null); // true console.log(undefined === null); // false
boolean 类型:只有两个字面值true false
。但是这两个值和数字值不是一回事,因此true
不一定等于1,而false
也不一定等于0。
要将一个值转为boolean
型等价的值,有两种方案:
-
一种是显式转换-调用类型转换函数Boolean()
-
一种是自动转换-如if(value)中的value就会自动转化成为boolean值
转换为true的值 | 转换为false的值 | |
---|---|---|
boolean | true | false |
string | 任何非空字符串 | "" (空字符串) |
bumber | 任何非零数字值(包括无穷大) | 0和NaN |
undefined | 无 | undefined |
null | 无 | null |
Object | 任何对象 | 无 |
number 类型:
表示整型,浮点型和NaN
在JS
中,0/0、NaN/0
会返回NaN
,其它数字/0
会返回Infinity
,不会报错。
isNaN()
console.log(NaN + 1); // NaN,任何涉及到NaN的操作都会返回NaN console.log(NaN === NaN); // false,NaN与任何值都不相等,包括NaN本身 console.log(isNaN(NaN)); // true,是NaN console.log(isNaN('10')); // false,被转为数字10 console.log(isNaN(true)); // false,被转为数字1 console.log(isNaN(null)); // false,被转为数字0 console.log(isNaN(undefined)); // true,返回NaN console.log(isNaN('hello')); // true,无法转换为数字 console.log(0/0);// NaN,0/0返回NaN console.log(NaN/0);// NaN,NaN/0返回NaN console.log(1/0);// Infinity,其它数字/0返回Infinity console.log('1'/0);// Infinity,'1'成功转为数字 console.log('1a'/0);// NaN,'1a'转为数字失败,变为NaN console.log(Infinity/0);// Infinity,其它数字/0返回Infinity
注意:Infinity的类型是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
-
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:
string类型用于表示由零或多个16位Unicode字符组成的字符序列,即字符串。字符串可以由单引号(')或双引号(")表示。任何字符串的长度都可以通过访问其length属性取得。
要把一个值转换为一个字符串有三种方式。
-
第一种是使用几乎每个值都有的
toString()
方法(除去null和undefined
没有)-
toString(radius)
有一个参数-基数,当需要toString
的值为number
时,参数可以生效(可以转换为对应进制输出,如10.toString(8)
输出为12。
-
-
第二种是隐式转换,比如字符串+ number(null,undefined,object等),会默认转为字符串(如果后面相加的是object对象,会返回object对象的toString或valueOf值)
-
第三种是通过转换函数
String()
,转换规则如下 -
如果值有
toString()
方法,则调用该方法(没有参数)并返回相应的结果(注意,valueOf()
方法没用) -
如果值是
null
,则返回null
-
如果值是
undefined
,则返回undefined
var a = 10; console.log(a.toString());//10 console.log(a.toString(8));//12 var b = '10' console.log(b.toString(8));//10,字符串基数没用 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__); // 原型
2.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
-
直接转换为true(包装类型也一样),不调用valueOf和toString
对象转换为数字
在预期会将对象用作数字使用时,比如参与算术运算等等操作,对象转换为数字会依次调用valueOf和toString方法,具体规则如下:
-
如果对象具有
valueOf
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字 -
如果对象具有
toString
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字 -
转换失败,抛出TypeError
对象转换为字符串
-
如果对象具有
toString
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串 -
如果对象具有
valueOf
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串 -
转换失败,抛出TypeError
toString
转换规则
对象 | toString返回值 |
---|---|
Array | 以逗号分割的字符串,如[1,2]的toString返回值为"1,2" |
Boolean | "True" |
Date | 可读的时间字符串,如"Tue Oct 15 2019 12:20:56 GMT+0800 (中国标准时间)" |
Function | 声明函数的JS源代码字符串 |
Number | "数字值" |
Object | "[object Object]" |
String | "字符串" |
Boolean.prototype.toString()
toString()
方法返回指定的布尔对象的字符串形式
let flag = new Boolean(true); console.log(flag.toString()) // true let flag1 = new Boolean(1); console.log(flag1.toString()) // true
Array.prototype.toString()
toString()
返回一个字符串,表示指定的数组及其元素。
let array = ['abc', true, 12, undefined, 'ok'] console.log(array.toString()); // abc,true,12,,ok
Function.prototype.toString()
toString()
方法返回一个表示当前函数源代码的字符串。
function fun(num) { num += 5 } console.log(fun.toString()); /** * function fun(num) { num += 5 } */
Object.prototype.toString()
toString()
let obj = { name: 'houfee'} console.log(obj.toString()); // [object Object]
3.对象到原始值的转换
对象转换为Boolean
// 保存原始的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(typeof b); // console.log(b); console.log(2); }
// 保存原始的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
分析
-
valueOf方法返回的是对象本身,不是原始值,继续执行
-
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 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 */
// 保存原始的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 + 'str'); // valueOf toString [object Object]str // alert(a) // alert主动调用toString方法,返回了字符串"[object Object]",对象最终转换为该字符串
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.不是!报错: * */
a.toString = function () {return {name: 'newName'}} // 让toString方法返回值为 复杂数据类型 a.toString() // 调用覆盖的方法 Number(a) // 报错
a.toString = function () {return '321'} // 让toString方法返回值为 复杂数据类型 a.toString() // 调用覆盖的方法 Number(a) // 321
所以Number强制转换对象的过程即为如上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]
-
-
判断该方法的返回值是否为基础数据类型(Number,String,Boolean,Undefined,Null)
-
若返回值为基础数据类型,则转换规则按照相应数据类型的转换规则对其进行转换
-
若返回值不为基础数据类型,则在该返回值的基础上继续调用valueOf方法
-
判断valueOf的返回值是否为基础数据类型
-
判断是否为基础数据类型,若是基础数据类型则进行操作3
-
若仍旧不为基础数据类型则报错
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([] + []) // 空字符串