共计 8364 个字符,预计需要花费 21 分钟才能阅读完成。
根底数据类型
转载请注明出处,github 地址 JavaScript 根底数据类型
js 中的数据类型
JavaScript
中共有七种内置数据类型,包含 根本类型 和对象类型。
根本类型
根本类型分为以下六种:
- string(字符串)
- boolean(布尔值)
- number(数字)
- symbol(符号)
- null(空值)
- undefined(未定义)
留神:
string
、number
、boolean
和null
undefined
这五种类型统称为 原始类型(Primitive),示意不能再细分上来的根本类型;symbol
是 ES6 中新增的数据类型,symbol
示意举世无双的值,通过Symbol
函数调用生成,因为生成的 symbol 值为原始类型,所以Symbol
函数不能应用new
调用;null
和undefined
通常被认为是非凡值,这两种类型的值惟一,就是其自身。
对象类型
对象类型也叫援用类型,array
和 function
是对象的子类型。对象在逻辑上是属性的无序汇合,是寄存各种值的容器。对象值存储的是援用地址,所以和根本类型值不可变的个性不同,对象值是可变的。
弱类型语言
JavaScript
是弱类型语言,而且 JavaScript
申明变量的时候并没有预先确定的类型,变量的类型就是其值的类型,也就是说 变量以后的类型由其值所决定 , 夸大点说上一秒种的String
,下一秒可能就是个Number
类型了,这个过程可能就进行了某些操作产生了强制类型转换。尽管弱类型的这种 不须要预先确定类型 的个性给咱们带来了便当,同时也会给咱们带来困扰,为了能充分利用该个性就必须把握类型转换的原理。
js 中的强制转换规则
ToPrimitive
(转换为原始值)
ToPrimitive
对原始类型不产生转换解决,只 针对援用类型(object)的,其目标是将援用类型(object)转换为非对象类型,也就是原始类型。
ToPrimitive
运算符 承受一个值,和一个可选的冀望类型作参数 。ToPrimitive
运算符将值转换为非对象类型,如果对象有能力被转换为不止一种原始类型,能够应用可选的 冀望类型 来暗示那个类型。
转换后的后果 原始类型 是由冀望类型决定的,冀望类型其实就是咱们传递的 type
。间接看上面比较清楚。ToPrimitive
办法大略长这么个样子具体如下。
/**
* @obj 须要转换的对象
* @type 冀望转换为的原始数据类型,可选
*/
ToPrimitive(obj,type)
type 不同值的阐明
- type 为
string
:
- 先调用
obj
的toString
办法,如果为原始值,则return
,否则进行第 2 步 - 调用
obj
的valueOf
办法,如果为原始值,则return
,否则进行第 3 步 - 抛出
TypeError
异样
- type 为
number
:
- 先调用
obj
的valueOf
办法,如果为原始值,则return
,否则进行第 2 步 - 调用
obj
的toString
办法,如果为原始值,则return
,否则第 3 步 - 抛出
TypeError
异样
- type 参数为空
- 该对象为
Date
,则 type 被设置为String
- 否则,type 被设置为
Number
Date 数据类型非凡阐明:
对于 Date
数据类型,咱们更多冀望取得的是其转为工夫后的字符串,而非毫秒值(工夫戳),如果为 number
,则会取到对应的毫秒值,显然字符串应用更多。
其余类型对象依照取值的类型操作即可。
ToPrimitive
总结
ToPrimitive
转成何种原始类型,取决于 type,type 参数可选,若指定,则依照指定类型转换,若不指定,默认依据实用状况分两种状况,Date
为string
,其余对象为number
。那么什么时候会指定 type 类型呢,那就要看上面两种转换形式了。
toString
Object.prototype.toString()
toString()
办法返回一个示意该对象的字符串。
每个对象都有一个 toString()
办法,当对象被示意为文本值时或者当以冀望字符串的形式援用对象时,该办法被主动调用。
这里先记住,valueOf()
和 toString()
在特定的场合下会自行调用。
valueOf
Object.prototype.valueOf()
办法返回指定对象的原始值。
JavaScript
调用 valueOf()
办法用来把对象转换成原始类型的值(数值、字符串和布尔值)。然而咱们很少须要本人调用此函数,valueOf
办法个别都会被 JavaScript
主动调用。
不同内置对象的 valueOf
实现:
- String => 返回字符串值
- Number => 返回数字值
- Date => 返回一个数字,即工夫值, 字符串中内容是依赖于具体实现的
- Boolean => 返回 Boolean 的 this 值
- Object => 返回 this
对照代码会更清晰一些:
var str = new String('123');
console.log(str.valueOf());//123
var num = new Number(123);
console.log(num.valueOf());//123
var date = new Date();
console.log(date.valueOf()); //1526990889729
var bool = new Boolean('123');
console.log(bool.valueOf());//true
var obj = new Object({valueOf:()=>{return 1}})
console.log(obj.valueOf());//1
Number
Number
运算符转换规则:
null
转换为 0undefined
转换为NaN
true
转换为 1,false
转换为 0- 字符串转换时遵循数字常量规定,转换失败返回
NaN
留神:对象这里要先转换为原始值,调用
ToPrimitive
转换,type 指定为number
了,持续回到ToPrimitive
进行转换。
String
String
运算符转换规则
null
转换为'null'
undefined
转换为undefined
true
转换为'true'
,false
转换为'false'
- 数字转换遵循通用规定,极大极小的数字应用指数模式
留神:对象这里要先转换为原始值,调用
ToPrimitive
转换,type
就指定为string
了,持续回到ToPrimitive
进行转换 (下面有将到ToPrimitive
的转换规则)。
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(Infinity) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,3]]) // '1,2,3'
String(['koala',1]) //koala,1
Boolean
ToBoolean
运算符转换规则
除了下述 6 个值转换后果为 false
,其余全副为 true
:
- undefined
- null
- -0
- 0 或 +0
- NaN
- ”(空字符串)
假值以外的值都是真值。其中包含所有对象(包含空对象)的转换后果都是 true
,甚至连false
对应的布尔对象 new Boolean(false)
也是true
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
转换规则不同场景利用
什么时候主动转换为 string 类型
- 在没有对象的前提下
字符串的主动转换,次要产生在字符串的 加法运算 时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
'2' + 1 // '21'
'2' + true // "2true"
'2' + false // "2false"
'2' + undefined // "2undefined"
'2' + null // "2null"
- 当有对象且与对象
+
时候
//toString 的对象
var obj2 = {toString:function(){return 'a'}
}
console.log('2'+obj2)
// 输入后果 2a
// 惯例对象
var obj1 = {
a:1,
b:2
}
console.log('2'+obj1);// 输入后果 2[object Object]
// 几种非凡对象
'2' + {} // "2[object Object]"
'2' + [] // "2"
'2' + function (){} // "2function (){}"
'2' + ['koala',1] // 2koala,1
对上面 '2'+obj2
具体举例说明如下:
- 右边为
string
,ToPrimitive
原始值转换后不发生变化 - 左边转化时同样依照
ToPrimitive
进行原始值转换,因为指定的 type 是number
,进行ToPrimitive
转化调用obj2.valueof()
, 失去的不是原始值,进行第三步 - 调用
toString()
return 'a'
- 符号两边存在
string
,而且是+
号运算符则都采纳String
规定转换为string
类型进行拼接 - 输入后果
2a
对上面 '2'+obj1
具体举例说明如下:
- 右边为
string
,ToPrimitive
转换为原始值后不发生变化 - 左边转化时同样依照
ToPrimitive
进行原始值转换,因为指定的 type 是number
,进行ToPrimitive
转化调用obj2.valueof()
, 失去{a: 1, b: 2}
- 调用
toString()
return [object Object]
- 符号两边存在
string
,而且是 + 号运算符则都采纳String
规定转换为string
类型进行拼接 - 输入后果
2[object Object]
代码中几种非凡对象的转换规则基本相同,就不一一阐明,大家能够想一下流程。
留神:不论是对象还不是对象,都有一个转换为原始值的过程,也就 是 ToPrimitive
转换,只不过原始类型转换后不发生变化,对象类型才会产生具体转换。
string 类型转换开发过程中可能出错的点:
var obj = {width: '100'};
obj.width + 20 // "10020"
预期输入后果 120 理论输入后果 10020
什么时候主动转换为 Number 类型
-
有加法运算符,然而无
String
类型的时候,都会优先转换为Number
类型例子:
true + 0 // 1 true + true // 2 true + false //1
- 除了加法运算符,其余运算符都会把运算主动转成数值。
例子:
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
// 一元运算符(留神点)+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
留神:
null
转为数值时为 0,而undefined
转为数值时为NaN
。
判断等号也放在 Number
外面非凡阐明
== 形象相等比拟与 + 运算符不同,不再是 String
优先,而是 Number
优先。
上面列举 x == y
的例子
- 如果
x
,y
均为number
,间接比拟
没什么可解释的了
1 == 2 //false
- 如果存在对象,
ToPrimitive()
type 为number
进行转换,再进行前面比拟
var obj1 = {valueOf:function(){return '1'}
}
1 == obj1 //true
//obj1 转为原始值,调用 obj1.valueOf()
// 返回原始值 '1'
//'1'toNumber 失去 1 而后比拟 1 == 1
[] == ![] //true
//[]作为对象 ToPrimitive 失去 ''
//![]作为 boolean 转换失去 0
//'' == 0
// 转换为 0==0 //true
- 存在
boolean
,依照ToNumber
将boolean
转换为 1 或者 0,再进行前面比拟
//boolean 先转成 number,依照下面的规定失去 1
//3 == 1 false
//0 == 0 true
3 == true // false
'0' == false //true
4. 如果 x
为string
,y
为 number
,x
转成 number
进行比拟
//'0' toNumber()失去 0
//0 == 0 true
'0' == 0 //true
什么时候进行布尔转换
- 布尔比拟时
if(obj)
,while(obj)
等判断时或者 三元运算符只可能蕴含布尔值
条件局部的每个值都相当于false
,应用否定运算符后,就变成了true
if ( !undefined
&& !null
&& !0
&& !NaN
&& !''
) {console.log('true');
} // true
// 上面两种状况也会转成布尔类型
expression ? true : false
!! expression
数据类型判断
面试官问:如何判断数据类型?怎么判断一个值到底是数组类型还是对象?
三种形式,别离为 typeof
、instanceof
和 Object.prototype.toString()
typeof
通过 typeof
操作符来判断一个值属于哪种根本类型。
typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 无奈断定是否为 null
typeof undefined // 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
下面代码的输入后果能够看出,
null
的断定有误差,失去的后果
如果应用 typeof
,null
失去的后果是object
- 操作符对对象类型及其子类型,例如函数(可调用对象)、数组(有序索引对象)等进行断定,则除了函数都会失去
object
的后果。
综上能够看出 typeOf
对于判断类型还有一些有余,在对象的子类型和 null
状况下。
instanceof
通过 instanceof
操作符也能够对对象类型进行断定,其原理就是测试构造函数的 prototype
是否呈现在被检测对象的原型链上。
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
复制代码留神:instanceof
也不是万能的。
举个例子:
let arr = []
let obj = {}
arr instanceof Array // true
arr instanceof Object // true
obj instanceof Object // true
在这个例子中,arr
数组相当于 new Array()
出的一个实例,所以 arr.__proto__ === Array.prototype
,又因为 Array
属于 Object
子类型,即 Array.prototype.__proto__ === Object.prototype
,因而 Object
构造函数在 arr
的原型链上。所以 instanceof
依然无奈优雅的判断一个值到底属于数组还是一般对象。
还有一点须要阐明下,有些开发者会说 Object.prototype.__proto__ === null
,岂不是说 arr instanceof null
也应该为 true
,这个语句其实会报错提醒右侧参数应该为对象,这也印证 typeof null
的后果为 object
真的只是 javascript
中的一个 bug
。
Object.prototype.toString()
Object.prototype.toString()
能够说是断定 JavaScript
中数据类型的终极解决办法了,具体用法请看以下代码:
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'
咱们能够发现该办法在传入任何类型的值都能返回对应精确的对象类型。用法虽简单明了,但其中有几个点须要了解分明:
- 该办法实质就是依靠
Object.prototype.toString()
办法失去对象外部属性[[Class]]
- 传入原始类型却可能断定出后果是因为对值进行了包装
null
和undefined
可能输入后果是外部实现有做解决
NaN 相干
NaN
的概念
NaN
是一个全局对象的属性,NaN
是一个全局对象的属性,NaN
是一种非凡的 Number
类型。
什么时候返回 NaN(开篇第二道题也失去解决)
- 无穷大除以无穷大
- 给任意正数做开方运算
- 算数运算符与不是数字或无奈转换为数字的操作数一起应用
- 字符串解析成数字
一些例子:
Infinity / Infinity; // 无穷大除以无穷大
Math.sqrt(-1); // 给任意正数做开方运算
'a' - 1; // 算数运算符与不是数字或无奈转换为数字的操作数一起应用
'a' * 1;
'a' / 1;
parseInt('a'); // 字符串解析成数字
parseFloat('a');
Number('a'); //NaN
'abc' - 1 // NaN
undefined + 1 // NaN
// 一元运算符(留神点)+'abc' // NaN
-'abc' // NaN
误区
toString
和 String
的区别
toString
-
toString()
能够将数据都转为字符串,然而null
和undefined
不能够转换。console.log(null.toString()) // 报错 TypeError: Cannot read property 'toString' of null console.log(undefined.toString()) // 报错 TypeError: Cannot read property 'toString' of undefined
toString()
括号中能够写数字,代表进制二进制:.toString(2);
八进制:.toString(8);
十进制:.toString(10);
十六进制:.toString(16);
String
-
String()
能够将null
和undefined
转换为字符串,然而没法转进制字符串console.log(String(null)); // null console.log(String(undefined)); // undefined