7. js中的八种数据类型、强制转换、如何判断js数据类型

目录

一、JS的数据类型有8种

1. Number

2. String

3. Boolean

4. Object

5. null

6. undefined

7. Symbol

8. bigInt

 二、强制类型转换

1. 其它类型转换为String

2. 其它类型转换为Number

3. 其它类型转换为Boolean:Boolean()

三、如何判断js数据类型(三种方法)

1. 方法一:typeof

2. 方法二:instanceof(instanceof 只能用来判断两个对象是否属于原型链的关系)

3. 方法三:constructor属性

4. 方法四:Object.prototype.toString.call()

5. 方法五:全等===

四、暂时性死区

1. 定义

2. ES6 暂时性死区的目的


一、JS的数据类型有8种

Number、String、Boolean、Object、Null、undefined、Symbol、bigInt

ES5中,有6种数据类型:Number、String、Boolean、Object、Null、undefined;

ES6中,又增加了一种数据类型:Symbol;

谷歌67版本中还出现了一种 :bigInt。指安全存储、操作大整数(目的是比Number数据类型支持的范围更大的整数值)。

其中,

基本类型:Number、String、Boolean、Null、undefined、Symbol

引用类型:Object (包含function、Array、Date、Math

1. Number

  • JS中所有的数值都是Numberl类型。包括整数和浮点数(小数)
  • 获取数字的最大值和最小值(Number.MAX_VALUE和Number.MIN_VALUE)。如果超过最大值,返回Infinity(表示无穷,Number类型)
  • NaN(Not a number):表示一个特殊的数字。任何值和NaN做比较都是false。

2. String

  • 字符串可以用单引号、双引号表示。但是同种引号不能嵌套
  • 在字符串中,使用\作为转义字符。\" 表示 "
  • 字符串是不可变的,一旦创建,值就不能改变
  •  要改变某个变量保存的字符串,首先要销毁原来的字符串,然后于用另一个包含的字符串填充该变量。

            

3. Boolean

  使用最多的一个类型,有两个字面值,分别是true(非0)、false(0)

4. Object

是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型名称来创建

5. null

null 是js的关键字,常用来描述空值,是一个对象

null是JavaScript语言的关键字,它表示一个特殊值,常用来描述“空值”。

6. undefined

undefined不是关键字,是预定义的全局变量,它的值就是“未定义”,表示值的空缺(表明变量没有初始化)。

在查询对象的属性或数组元素的值时返回undefined,则说明这个属性或元素不存在;


 

7. Symbol

Symbol 类型的对象永远不相等,即便创建的时候传入相同的值。因此,可以用解决属性名冲突的问题(适用于多少编码),做为标记。

Symbol 数据类型在 ES6 中起什么作用? - 简书

ES6 入门教程(介绍了symbol类型)

  • 凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突相同参数的Symbol函数的返回值是不相等的。
  • Symbol函数前不能使用new命令,这是因为生成的 Symbol 是一个原始类型的值,不是对象
  • Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
  • 由于以 Symbol 值作为键名不会被常规方法遍历得到(for...infor...of,Object.keys()都不可遍历到;但使用Object.getOwnPropertySymbols()方法可访问)。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
  • Symbol.for()Symbol()都会生成新的 Symbol。它们的区别是,Symbol.for()会被登记全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。
  • 对象进行for...of循环时,会调用Symbol.iterator方法。对象的Symbol.iterator属性,指向该对象的默认遍历器方法。

  • Symbol 值不能与其他类型的值进行运算,会报错。(Symbol 值也可以转为布尔值,但是不能转为数值。)
  • Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的
  • Symbol 值作为对象属性名时不能用点运算符,因为点运算符后面总是字符串Symbol 值必须放在方括号之中。如果s不放在方括号中,该属性的键名就是字符串s,而不是s所代表的那个 Symbol 值。

特性:唯一性

(1)创建Symbol类型的变量(其中()内的参数用来描述Symbol)

注意:<1> 使用 Symbol() 函数创建,不会在你的整个代码库中创建一个可用的全局 symbol类型

          <2>使用Symbol.for() 方法,可创建全局symbol类型

(2)使用[],进行赋值和取值

(3)好处(作用):

<1> Symbol类型的属性名不能通过Object.属性名和for...in来访问(避免一些)。但是对象具有Symbol.iterator属性,就是可遍历的

         

<2>使用Symbol来代替常量

  

<3> 在对象内,可以模拟私有属性,无法被轻易覆盖。

8. bigInt

BigInt数据类型是为了让JavaScript程序能表示超出Number 类型支持的数值范围。

在对大整数进行数学运算时,以任意精度表示整数的能力尤为重要。有了BigInt,整数溢出将不再是一个问题,是 chrome 67中的新功能。

(1)创建:BigInt()  或  通过在一个整数字面量后面加 n 的方式定义一个 BigInt 

9、null和undefined的区别

  1. null(已初始化,赋值为null):访问一个尚未存在的对象时所返回的值。是javascript的关键字,可以认为是对象类型,它是一个空对象指针,和其它语言一样都是代表“空值”。
  2. undefined(未初始化,即未赋值) :访问一个未初始化的变量时返回的值。只有JS才有。为了区分空指针对象未初始化的变量,它是一个预定义的全局变量。没有返回值的函数返回为undefined,没有实参的形参也是undefined。
  3. null 和 undefined 的值相等,但不全等
typeof undefined             // undefined
typeof null                  // object
null === undefined           // false
null == undefined            // true

 二、强制类型转换

主要是指将其它数据类型转换为String、Number、Boolean

1. 其它类型转换为String

(1)方法一:toString()方法 (前面需要加.)

注意:<1> 该方法不会影响到原变量,会将转换的结果返回

          <2> null 和 undefined这两个值没有toString()方法

        

toString的具体用法:Javascript toString 方法原理_josavion的博客-CSDN博客

(2)方法二:String()函数

2. 其它类型转换为Number

(1)方法一:Number()函数,不会改变本身

      <1> 字符串转换为数字: 

  • 如果是纯数字的字符串   ,则直接转换为数字
  • 如果字符串中有非数字的内容,则转化为NaN
  • 如果字符串是一个空串或一个全是空格的字符串,则转换为0

     

      <2> 布尔转换为数字:    

  • true转换为1
  • false转换为0

      <3> Null 转换为数字: 0

      <4> undefined转换为数字: NaN

(2)方法二:parseInt(将字符串转化为整数) 和 parseFloat(将字符串转化为浮点数)

如果对非Strings使用上述方法进行转换,它会先将其转换为String类型,再转为数字

parseInt方法接收两个参数,parseInt(要被解析的值string,被解析的值的进制);

  • string:要被解析的值。如果参数不是一个字符串,则将其转换为字符串(toString)。字符串开头的空白符将会被忽略。
  • radix:可选,默认是十进制。从 2 到 36,表示被解析的值的进制。例如说指定 10 就等于指定十进位。

 1.基本用法,只接受一个参数,可以当做第二个参数默认是10。parseInt的返回值只有两种可能,不是一个十进制整数,就是NaN。

a.将字符串转为整数。

parseInt('123'); // 123

b.如果字符串头部有空格,空格会被自动去除。

parseInt('  81'); // 81

c.如果parseInt的参数不是字符串,则会先转为字符串再转换。这个很重要

d.字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。

parseInt('99aa'); // 99

e.如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。

parseInt('aa99'); // NaN
parseInt('-99'); // -99

f.如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。

parseInt('0x10'); // 16

g.如果字符串以0开头,将其按照10进制解析。

parseInt('011') // 11

h.如果参数以0开头,但不是字符串,则会先将数值转成字符串,然后解析,见规则c;

parseInt(011); // 9
// 解释一下,(011).toString()得到的结果是‘9’,具体原因请查看我的博文中有介绍toString方法

i.对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。

parseInt(1000000000000000000000.5); // 1
// 等同于
parseInt('1e+21'); // 1
 
parseInt(0.0000008); // 8
// 等同于
parseInt('8e-7'); // 8


 
 

2.进制转换(接收两个参数),parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。

a.第一个参数解析规则参照第一条基本用法
b.如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN。如果第二个参数是0、undefined和null,则直接忽略。
parseInt(“19”, 10); // 19 (10+9)
parseInt(“11”, 2); // 3 (2+1)
parseInt(“17”, 8); // 15 (8+7)
parseInt(“1f”, 16); // 31 (16+15)
 
parseInt('-99', null); // -99
parseInt('-99', undefined); // -99
parseInt('-99', 0); // -99

 

3. 其它类型转换为Boolean:Boolean()

(1)数字转换为布尔:除了0和NaN,其余都是true

(2)字符串转换为布尔:除了空串,其余都是true

(3)对象也会转换为true

补充:只有下面五种情况,转换为Boolean类型,值为false:

1)NaN   

2)0

3)‘’

4)undefined

5)null

三、如何判断js数据类型(三种方法)

1. 方法一:typeof

typeof 返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、object、undefined、function等6种数据类型。

缺点:

typeof 可以对JS基础数据类型做出准确的判断(除了null),而对于引用类型返回的基本上都是object。其实返回object也没有错,因为所有对象的原型链最终都指向了Object,Object是所有对象的`祖宗`。

我们需要知道某个对象的具体类型时,typeof 就显得有些力不从心了。

typeof  '' ;  // string 有效
typeof  1;  // number 有效
typeof  true ;  //boolean 有效
typeof  undefined;  //undefined 有效

typeof  null ;  //object 无效
typeof  [] ;  //object 无效
typeof  new  Function();  // function 有效
typeof  new  Date();  //object 无效
typeof  new  RegExp();  //object 无效

为什么 typeof null 时会返回object:

js中不同对象在底层都表示为二进制,而javascript 中会把二进制前三位都为0的判断为object类型,而null的二进制表示全都是0,自然前三位也是0,所以执行typeof时会返回'object。

补充:js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息

  • 000:对象
  • 010:浮点数
  • 100:字符串
  • 110:布尔
  • 1:整数

用 instanceof 来判断null的话会报错:

null instanceof null // TypeError: Right-hand side of 'instanceof' is not an object

2. 方法二:instanceof(instanceof 只能用来判断两个对象是否属于原型链的关系)

instanceof 是用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。

在这里需要特别注意的是:instanceof检测的是原型,我们用一段伪代码来模拟其内部执行过程:

instanceof (A,B) = {
     var  L = A.__proto__;
     var  R = B.prototype;
     if (L === R) {
         //A的内部属性__proto__指向B的原型对象
         return  true ;
     }
     return  false ;
}

从上述过程可以看出,当 A 的 __proto__ 指向 B 的 prototype 时,就认为A就是B的实例,我们再来看几个例子:

[] instanceof Array;  //true
{} instanceof Object; //true
new  Date() instanceof Date; //true
 
function Person(){};
new  Person() instanceof Person; //true

// 只能判断 两个对象是否属于原型链的关系
[] instanceof Object;  //true
new  Date() instanceof Object; //true
new  Person instanceof Object; //true

我们发现,虽然 instanceof 能够判断出 [] 是Array的实例,但它认为 [] 也是Object的实例,为什么呢? 我们来分析一下[]、Array、Object 三者之间的关系:

从instanceof 能够判断出 [].__proto__ 指向 Array.prototype, 而 Array.prototype.__proto__ 又指向了Object.prototype,Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[]、Array、Object就形成了如下图所示的一条原型链:

从原型链可以看出,[] 的 __proto__  直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。

当然,类似的new Date()、new Person() 也会形成这样一条原型链,

因此缺点:instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。

instanceof 的实现原理:

只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。

3. 方法三:constructor属性

<1> 构造函数F的显式原型prototype含有constructor属性(指向构造函数F的引用),

<2> 创建构造函数F的实例对象f,对象f的隐式原型__proto__ 指向 构造函数F的显式原型prototype,故对象f中含有constructor属性(指向构造函数F)。

<3> 所以我们可以通过判断该对象的constructor属性 是否等于 构造函数F,来确定该对象的数据类型。

当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。如下所示:

当执行 var f = new F() 时,创建构造函数F的实例对象f,此时F原型上的constructor传递到了f上,因此f.constructor == F

可以看出,JS在函数F的原型上定义了constructor,当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型,使得新对象有名有姓,可以追溯。

同理,JS中的数据类型也遵守这个规则:

细节问题:

  • null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
  • JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

为什么变成了Object?

prototype被重新赋值的是一个{}, {}是new Object()的字面量,因此new Object()会将Object原型上的constructor传递给{},也就是Object本身。

因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写。

4. 方法四:Object.prototype.toString.call()

一般数据类型都能够判断,最准确最常用的一种

需要通过call方法,绑定toString的this指向。toString方法运行时,会返回this指向的具体类型。

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。 

Object.prototype.toString.call( '' ) ;    // [object String]
Object.prototype.toString.call(1) ;     // [object Number]
Object.prototype.toString.call( true ) ;  // [object Boolean]
Object.prototype.toString.call(undefined) ;  // [object Undefined]
Object.prototype.toString.call( null ) ;  // [object Null]
Object.prototype.toString.call( new  Function()) ;  // [object Function]
Object.prototype.toString.call( new  Date()) ;  // [object Date]
Object.prototype.toString.call([]) ;  // [object Array]
Object.prototype.toString.call( new  RegExp()) ;  // [object RegExp]
Object.prototype.toString.call( new  Error()) ;  // [object Error]
Object.prototype.toString.call(document) ;  // [object HTMLDocument]
Object.prototype.toString.call(window) ;  //[object global] window是全局对象global的引用

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。

5. 方法五:全等===

四、暂时性死区

1. 定义

ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

2. ES6 暂时性死区的目的

ES6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易了。

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值