ECMAScript5
中有五种基本数据类型:Undefined,Null,Boolean,Number,String
,以及一种复杂(引用类型)数据类型:Object
,Object
中还细分了不少具体的类型,好比:Array, Function, Date
等等;ECMAScript6
中又新增了一种Symbol
类型。es6
typeof
操做符typeof
是操做符,而不是函数,它可能返回:编程
"undefined"
:若是这个值未定义"boolean"
:若是这个值是布尔值"string"
:若是这个值是字符串值"number"
:若是这个值是数值"object"
:若是这个值是对象或者null
"function"
:若是这个值是函数"symbol"
:若是这个值是Symbol
值函数在ECMAScript
中是对象,不是一种数据类型;可是函数却也有一些特殊的属性,因此经过typeof
来区分对象和函数是有必要的安全
Undefined
类型Undefined
类型只有一个值 —— undefined
,当一个变量仅声明而未初始化时,这个变量的值就是undefined
(当一个变量未声明(未定义)时,若是访问它将会报错)函数
var a; let b; console.log(a,b);//undefined undefined console.log(c);//ReferenceError: c is not defined
在ES6
以前,typeof
是一个百分之百安全的操做,由于即便是对于未声明的变量,typeof
会返回"undefined"
,而不会报错。测试
可是ES6
引入了let,const
来声明变量,这两个命令没有声明提高,必定要在声明语句以后才能使用,不然就会报错;并且let,const
还存在暂时性死区:this
只要块级做用域内存在let或const命令,它所声明的变量就“绑定”(binding)这个区域,再也不受外部的影响。
ES6 明确规定,若是区块中存在let或const命令,这个区块对这些命令声明的变量,从一开始就造成了封闭做用域,凡是在声明以前就使用这些变量,就会报错
let tmp = 123; if (true) { tmp = 'abc'; // ReferenceError: tmp is not defined let tmp; }
上面的代码中存在全局变量tmp
,可是块级做用域内let
又声明了一个局部变量tmp
,致使后者绑定这个块级做用域,因此在let
声明变量前,对tmp
赋值会报错。编码
因此“暂时性死区”也意味着typeof
再也不是一个百分之百安全的操做,这样的设计是为了让你们养成良好的编程习惯,变量必定要在声明以后使用,不然就报错spa
Null
类型Null
类型只有一个值 —— null
,从逻辑角度来看,null
表示一个空对象指针,这也是用typeof
操做符检测null
会返回"object"
的缘由。prototype
undefined
值是派生自null
值的,因此undefined == null
会返回true
,可是它们二者的用途彻底不一样。设计
只要意在保存对象的变量尚未真正保存对象,就应该让该变量保存null
值,这样作不只能够体现null
做为空指针对象的惯例,还有助于区分null
和undefined
。
Boolean
类型Boolean
类型有两个字面值,表示真的true
和表示假的false
;ECMAScript
中全部类型的值都有与这两个Boolean
值等价的值,能够经过Boolean()
函数转换
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""空字符串 |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | 不适用 | undefined |
Symbol | 任何 | 不适用 |
Number
类型Number
类型的数值字面量格式有八进制(严格模式下使用八进制将会报错)、十进制和十六进制,其中八进制字面值的第一位必须为0
,十六进制前两位必须为0x
。在进行算术计算时,八进制和十六进制都会转换为十进制。
Number
类型使用IEEE754
标准定义的64位浮点数表示,存储为8字节,使用时不区分整数与浮点数,1与1.0是同样的,存储状况以下:
其中尾数位即有效数字部分,IEEE754
规定,有效数字第一位默认老是1,即有效数字老是1.xx...xx的形式,其中第一位不进行存储,而xx..xx的部分保存在64位浮点数之中,最长可能为52位。所以,JavaScript
实际提供的有效数字最长为53个二进制位,一个数字能够表示为:
(-1)^符号位 * 1.xx...xx * 2^指数位
有效数字精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即在-(Math.pow(2, 53) - 1
到 Math.pow(2, 53) - 1
范围内的整数均可以精确表示(安全整数),而不在该范围内的整数则会丧失精度。
es6
中增长了Number.MAX_SAFE_INTEGER
及Number.MIN_SAFE_INTEGER
来表示安全整数范围的上下限,还增长了方法Number.isSafeInteger
来判断是否处于安全整数范围内。
浮点数的最高精度是17
位小数,可是计算时的精度远远不如整数,浮点数值计算会产生舍入偏差的问题,这是使用基于IEEE754
数值的浮点计算的通病,因此永远不要测试某个特定的浮点数数值。
Number
类型的数值范围是Number.MIN_VALUE ~ Number.MAX_VALUE
,超出这个范围的值为Infinity
,可使用isFinite()
函数来判断数值是否在范围内。
Number
类型有一个特殊的值——NaN(Not a Number)
他表示一个原本要返回数值的操做数却未返回数值的状况,NaN
是数字类型 可是不是数字,他有两个特色
NaN
的操做都会返回NaN
NaN
与任何值都不相等,包括它本身0
处于0
返回NaN
,其余的除以0
返回infinity
或-infinity
NaN
的布尔值是false
isNaN()
函数能够判断传入的参数是否“不是数值”,判断前会自动调用Number()
进行转换,转换后再进行判断,任何不能转换为数值的值都会致使这个函数返回true
;这个函数也适用于对象,在基于对象调用它时,会先调用对象的valueOf()
方法,而后肯定该方法的返回值是否能够转换为数值。若是不能,则基于这个返回值再调用toString()
方法,再测试返回值有如下几种方法能够把非数值转换为数值
Number()
函数
undefined
值,返回NaN
0
会忽略,若是字符串包含了除数值,0x
之外的字符将会返回NaN
valueOf()
方法,而后肯定该方法的返回值是否能够转换为数值。若是不能,即返回值是NaN
,则基于这个返回值再调用toString()
方法,再去转换返回的字符串值parseInt()
函数
NaN
。因此转换空字符串返回NaN
ECMAScript 3
和ECMAScript 5
在解析八进制字面量字符时有分歧,ECMAScript 5
中的parseInt()
已经不具有解析八进制的能力,前导0
会被忽略,因此最好指定进制数,也就是第二个参数)parseFloat()
函数
NaN
。0
,它只解析十进制值,因此它只有一个参数。若是是十六进制会返回0
,由于十六进制的0x
,parseFloat()
函数只会解析到0
~
符号(按位非)
1
对于NaN
、Infinity
,应用位操做符会被当作0
来处理
console.log(~NaN);// -1 console.log(~Infinity);// -1
非数值应用位操做符时会先使用Number()
函数将该值转换为数值,在应用位操做符
console.log(~"12");// -13 console.log(~"w12");// -1
若是是对浮点数应用位操做符,将会对其取整(直接把小数点舍去的这种取整),再应用位操做符
console.log(~1.2);// -2 console.log(~-1.2);// 0
~~
符号(两次按位非)
++
、--
,能够转换数据类型,是按Number()
函数来转换的
++/--
后面的内容按Number
函数转换,再加减var a = "0xf"; a++; console.lgo(a);// 16
+
、-
能够转换数据类型,将其余的转为数字类型
Number()
函数来转换的+
号前面没有其余东西时,+
字符串会按照Number()
函数来转换字符串,其余的时候是字符串链接-
转换后,会在转换后的数值前加上负号,因此都是用+
好来转换String
类型String
类型表示由零个或多个16
位Unicode
字符组成的字符序列——字符串,JavaScript
建立的时候,Unicode
是一个16
位字符集,因此JavaScript
中的字符都是16
位的,采用UCS-2
编码方式(关于Unicode
的知识能够参见)
字符串是不可变的,一旦建立,值就不能改变;要改变就要先销毁原来的字符串(销毁过程在后台完成),再用另外一个包含新值的字符串填充该变量
String
类型包含一些特殊的字符字面量,好比\n,\t,\b,\xnn,\unnnn
等,他们称为转义序列,能够出如今字符串的任意位置,将被当作一个字符来解析;可是若是包含双字节字符,字符串将解析错误,length
也将返回错误的结果
var a = "Look this: \b"; var b = "Look this: \u20BB7"; console.log(a,a.length);//"Look this: " 12 console.log(b,b.length);//"Look this: 7" 13
为了解决这个问题,ES6
中对字符的Unicode
表示法作了改进,只要将Unicode
码点放入大括号,就能正确解读该字符,可是length
属性仍是返回错误,若想要正确的能够经过Array.form(xx).length
var b = "Look this: \u{20BB7}"; console.log(b,b.length);//"Look this: 𠮷" 13 console.log(Array.form(b).length);// 12
有如下几种方法能够把非字符串值转换为字符串值
toString()
方法
null
和undefined
没有这个方法String()
方法
null
和undefined
)toString
方法,就调用这个null
返回"null"
,是undefined
返回"undefined"
+
符号
Object
类型ECMAScript
中的对象是一组数据和功能的集合,Object
类型是全部它的实例的基础,即Object
类型所具备的任何属性和方法也存在于更具体的对象中
每一个Object
实例都具备如下属性和方法
constructor
:保存着用于建立当前对象的函数(构造函数)
var s = "cc"; var b = true; console.log(s.constructor);//ƒ String() console.log(b.constructor);//ƒ Boolean()
hasOwnProperty(propertyName)
:检查一个对象自身(不包括原型链)是否具备指定名称的属性。若是有,返回true
,不然返回false
,参数必须为字符串prototypeObject.isPrototypeOf( object )
:检查prototypeObject
是否存在于object
的原型链中propertyIsEnumerable
:检查给定的属性是否可以用for-in
语句来枚举,参数必须为字符串
false
,能够理解为它只是继承了这个属性可是没有真的属于他本身,因此就不能枚举toLocalString
:返回对象的字符串表示,与执行环境的地区对应toString
:返回对象的字符串表示valueOf
:返回对象的字符串、数值或布尔值表示Symbol
类型这个类型表示独一无二的值,经过Symbol()
函数生成,能够做为属性名,凡是属性名属于 Symbol
类型,就都是独一无二的,能够保证不会与其余属性名产生冲突。
Symbol()
函数能够接受一个字符串做为参数,表示对Symbol
实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。若是Symbol()
的参数不是字符串,就会调用toString
方法,将其转为字符串,而后才生成一个 Symbol
值。注意,Symbol
函数的参数只是表示对当前 Symbol
值的描述,所以相同参数的Symbol
函数的返回值是不相等的。
let s1 = Symbol('foo'); let s2 = Symbol('foo'); s1 === s2 // false
Symbol
值不能与其余类型的值进行运算,会报错,在模板字符串中也不能使用Symbol
值;
let s = Symbol('My symbol'); "your symbol is " + s // TypeError: Cannot convert a Symbol value to a string `your symbol is ${s}` // TypeError: Cannot convert a Symbol value to a string s + 1 // TypeError: Cannot convert a Symbol value to a number
可是它能够显式转换为字符串值、布尔值,可是不能转换为数值
let s = Symbol('My symbol'); String(s) // "Symbol(My symbol)" s.toString() // "Symbol(My symbol)" Boolean(s) // true Number(s) // TypeError: Cannot convert a Symbol value to a number
Symbol
值能够用于对象的属性名,能够能保证不会出现同名的属性,此时不能用点运算符,只能用方括号:
const mySymbol = Symbol(); const a = {}; a.mySymbol = "Hello"; a[mySymbol] = "World!" console.log(a['mySymbol']); // "Hello" console.log(a[mySymbol]); // "World!"
由于点运算符后面老是字符串,因此不会读取mySymbol
做为标识名所指代的那个值,致使a
的属性名其实是一个字符串,而不是一个 Symbol
值。
Symbol
做为属性名,该属性不会出如今for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。可是,它也不是私有属性,有一个Object.getOwnPropertySymbols
方法,能够获取指定对象的全部 Symbol
属性名。Reflect.ownKeys
方法能够返回全部类型的键名,包括常规键名和 Symbol 键名。
Symbol.for
方法能够作到从新使用同一个Symbol
值。它接受一个字符串做为参数,而后搜索有没有以该参数做为名称的 Symbol
值。若是有,就返回这个 Symbol
值,不然就新建并返回一个以该字符串为名称的 Symbol
值
let s1 = Symbol.for('foo'); let s2 = Symbol.for('foo'); s1 === s2 // true
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol
。它们的区别是:前者会被登记在全局环境中供搜索,后者不会
Symbol.for()
不会每次调用就返回一个新的 Symbol
类型的值,而是会先检查给定的key
是否已经存在,若是不存在才会新建一个值Symbol()
写法没有被登记,每次调用都会返回一个新的 Symbol
类型的值,每次的都是不一样的值Symbol.for
为 Symbol
值登记的名字,是全局环境的,能够在不一样的 iframe
或 service worker
中取到同一个值Symbol.for("bar") === Symbol.for("bar") // true Symbol("bar") === Symbol("bar") // false
Symbol.keyFor
方法返回一个已登记的 Symbol
类型值的key
,也就是返回使用Symbol.for
生成的Symbol
类型值的key
,若是没有传参数则返回"undefined"
;对于Symbol()
生成的Symbol
类型值返回undefined
let s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" let s2 = Symbol.for(); Symbol.keyFor(s3) // "undefined" let s3 = Symbol("foo"); Symbol.keyFor(s3) // undefined
typeof 变量 //"undefined"/"boolean"/"number"/"string"/"object"/"function"/"symbol"
typeof
能够正确检测出Number, String, Boolean, Undefined, Symbol
类型,但Array, Null, Date, Reg, Error
所有被检测为Object
类型,也就是说不能检测出Object
类型下的细分类型
变量 instanceof 类型 //true or false
instanceof
方法要求开发者明确地确认对象为某特定类型,它能够检测Object
类型下的细分类型,便可以正确检测出Array,Function,Date,Reg,Error
类型,以及使用new
操做符建立的Number, String, Boolean
类型(对于普通的字面量形式的Number, String, Boolean
没法检测)。
instanceof
没法检测Null, Undefined, Symbol
类型,老是会返回false
,因此使用instanceof
进行变量检测时,须要首先判断是不是Null, Undefined, Symbol
类型
instanceof
不能跨iframe
(每一个页面的类型原生对象所引用的地址是不同的)
变量.constructor == 类型 //true or false
constructor
原本是原型对象上的属性,指向其构造函数。可是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,所以,实例对象也是能使用constructor
属性的
constructor
能够正确检测Null, Undefined
以外的全部类型,包括Symbol
类型,Null, Undefined
没有constructor
属性
使用constructor
不是保险的,由于constructor
属性是能够被修改的,会致使检测出的结果不正确
constructor
不能跨iframe
(每一个页面的类型原生对象所引用的地址是不同的)
Object.prototype.toString.call(变量) == "[object 类型]" //true or false
Object.prototype.toString.call
的行为:
[[Class]]
[[Class]]
这个属性,返回一个相似于"[object Array]"
的字符串做为结果call
能够取得任何对象的内部属性[[Class]]
,而后把类型检测转化为字符串比较,以达到咱们的目的这个方法能够检测出全部的类型,包括Null,Undefined
、Object
下的细分类型以及Symbol
类型
jQuery
中$.type
的实现jQuery
就是用Object.prototype.toString.call
结合typeof
实现的
typeof
进行检测typeof
返回"object"
或者"function"
时,再使用Object.prototype.toString.call
来检测因此除了Object
和Function
,其余的都是使用typeof
进行检测