六大数据类型
- 值类型(原始类型) —— 栈内存存储
number、string、boolean、null、undefined、Symbol(ES6) - 引用类型(对象类型) —— 栈内存存储指向堆内存存储位置的指针,堆内存存储内容
object(Function、Array、Date、Regexp…)
隐式类型转换
加减运算符
5 + '5'
→ String5 - '5'
→ Number
* 加减运算符作为单目运算符时的情况:一律转换为数字,减号识别为负号+[]
→ 0+[1]
→ 1+[0, 1]
→ NaN+{}
→ NaN-[]
→ -0-[1]
→ -1-[0, 1]
→ NaN-{}
→ NaN
点运算符
通过点运算符访问值类型的属性或调用其方法时,先将值类型转换为对应的临时对象类型:(这类对象可称为包装对象)
number → new Number()
boolean → new Boolen()
string → new String()
再访问ga该临时对象的属性或调用其方法,使用完毕后,则销毁该临时对象。
1 | var str1 = "test" var str2 = new String("test") |
* 原型链读取时,以自身属性优先。str1 == str2
→ truestr1 === str2
→ false
关系运算符
==
/!=
存在隐式类型转换,转换为数字进行比较===
/!==
不转换,类型不一致则判断false
* undefined和null与任何有意义的值比较返回的都是false,但是null与undefined之间互相比较返回的是true:undefined == false
→ falsenull == false
→ falseundefined == null
→ true
if() 条件判断
转换为布尔值用于判断
显式类型转换
Number()、String()、Boolean()…
Number("123.1")
→ 123.1Number("123.1a")
→ NaN
parseInt(string, radix)、parseFloat(string)
- string
– 只有string中的第一个数字会被解读
– 开头和结尾的空格会被自动忽略
– string的第一个非空格字符若不是数字,则返回NaN - radix
– 解析数字的基数,取值[2, 36]
– 若省略,则以10为基数;若string的数字以”0x”或”0X”开头,则以16为基数
– 若取值超出[2, 36]的范围,则返回NaN
parseInt("17",8)
→ 15 —— 1*8+7parseInt("0x17")
→ 23 —— 1*16+7parseFloat(" 17.12 ")
→ 17.12parseFloat("0x17")
→ 0parseFloat("34 45 66")
→ 34parseFloat("40 years")
→ 40parseFloat(" He was 40 ")
→ NaN
取反(!)、双重取反(!!)
转换为布尔型
类型转换运作模式
转换总表
原始值 | 转换为字符串 | 转换为数字 | 转换为布尔型 | 转换为对象 |
---|---|---|---|---|
undefined | “undefined” | NaN | false | Throw Error |
null | “null” | 0 | false | Throw Error |
true | “true” | 1 | - | New Boolean(true) |
false | “false” | 0 | - | New Boolean(false) |
“” | - | 0 | false | New String(“”) |
“0” | - | 0 | true | New String(“0”) |
“1.2” | - | 1.2 | true | New String(“1.2”) |
“zero” | - | NaN | true | New String(“zero”) |
0 | “0” | - | false | New Number(0) |
1 | “1” | - | true | New Number(1) |
NaN | “NaN” | - | false | New Number(NaN) |
{} | “[object Object]” | 比较复杂 | true | - |
[] | “” | 0 | true | - |
[1] | “1” | 1 | true | - |
[0, 1] | “0,1” | NaN | true | - |
function(){} | “function (){}” | NaN | true | - |
* 注意:new Boolean(false)是一个对象,转换为布尔型时为true |
类型转换规律
1. toString()转换为字符串
[1,2,3].toString()
→ “1,2,3”(function(x){f(x);}).toString()
→ “function(x){f(x);}”new Date(2017,1,14).toString()
→ “Tue Feb 14 2017 00:00:00 GMT+0800 (中国标准时间)”/\d{9}/.toString()
→ “/\d{9}/“({x:0,y:1}).toString()
→ “[object object]”
2. valueOf()方法规律
若存在原始值,则转换为它的原始值;
非日期类型的对象多为复合值,无法真正表示成一个原始值,则简单地返回对象本身(如:数组、函数、正则表达式);
日期类型的对象返回从1970年1月1日以来总的毫秒数。new Number(1).valueOf()
→ 1 —— [Number]new Number('1').valueOf()
→ 1 —— [Number]new Number('a').valueOf()
→ NaN —— [Number]new Boolean(false).valueOf()
→ false —— [Boolean]new Boolean('a').valueOf()
→ true —— [Boolean][1,2,3].valueOf()
→ [1, 2, 3] —— [Array](function(x){f(x);}).valueOf()
→ ƒ(x){f(x);} —— [Function]new Date(2017,1,14).valueOf()
→ 1487001600000 —— [Number]/\d{9}/.valueOf()
→ /\d{9}/ —— [RegExp]({x:0,y:1}).valueOf()
→ {x: 0, y: 1} —— [Object]
3. 转换字符串或数字的步骤
转换为字符串的具体步骤:
Step1 尝试调用toString()方法,如果方法存在且返回一个原始值(值类型),则将这个值转换为字符串,作为最终结果。
Step2 尝试调用valueOf()方法,如果方法存在且返回一个原始值(值类型),则将这个值转换为字符串,作为最终结果。
Step3 如果toString()和valueOf()均调用失败,则抛出一个类型错误。
转换为数字的具体步骤:
Step1 尝试调用valueOf()方法,如果方法存在且返回一个原始值(值类型),则将这个值转换为数字,作为最终结果。
Step2 尝试调用toString()方法,如果方法存在且返回一个原始值(值类型),则将这个值转换为数字,作为最终结果。
Step3 如果toString()和valueOf()均调用失败,则抛出一个类型错误。
- 空数组转数字的过程:
[]
先调用valueOf()
,获得[]
,不是原始值;
则再调用toString()
,获得""
,是原始值,转换为数字0
输出。 [] == false
→ true ——[]
与false均转化为数字0
进行比较![] == false
→ true ——[]
先转换为布尔型true
取反,再转换为数字0
与false
转换的数字0
进行比较
关系、算术运算符至少有一侧为对象类型时
1) 对于非日期类型的对象,先调用valueOf(),再调用toString(),直到获得原始值,再根据运算需要转换类型;
2) 对于日期类型的对象,如果是+、==、!=运算符,则调用toString()获得原始值,其他运算符(如减号、大于号、小于号),则调用valueOf()获得原始值,再参与运算:new Date(2017, 1, 1) == 1485878400000
→ falsenew Date(2017, 1, 1) == 'Wed Feb 01 2017 00:00:00 GMT+0800 (中国标准时间)'
→ truenew Date(2017, 1, 1) + 1
→ “Wed Feb 01 2017 00:00:00 GMT+0800 (中国标准时间)1”new Date(2017, 1, 1) - 1
→ 1485878399999new Date(2018, 0, 1) < new Date(2017, 2, 1)
→ false"Mon Jan 01 2018 00:00:00 GMT+0800 (中国标准时间)" < "Wed Mar 01 2017 00:00:00 GMT+0800 (中国标准时间)"
→ true
类型判别方法
1. typeof
一元运算符,置于一个运算数之前:typeof 检测对象
,检测对象也可以用()
包裹;
运算结果是一个字符串,表示运算数的类型:
检测对象 | 检测结果 |
---|---|
undefined | “undefined” |
null | “object” |
true | “boolean” |
123 | “number” |
NaN | “number” |
“123” | “string” |
[] | “object” |
{} | “object” |
function(x){f(x);} | “function” |
Symbol类型变量(ES6新类型) | “symbol” |
总结:typeof()可以判别原始类型(除null),不能判断对象类型(除function) | |
应用场景: | |
- 判断一个变量是否存在 | |
if(typeof a != "undefined") (不使用if(a) 可防止a变量未声明而报错) |
|
- 判断document.getElementsByTagName是否获取到对象 | |
if(typeof(list.length) != "undefined" ) 或if(!isNaN(list.length)) |
2. instanceof
二元运算符,object(要检测的对象) instanceof constructor(某个构造函数)
,判断检测对象的原型链中是否存在构造函数的prototype属性,即判断某个对象是不是另一个对象的实例。
仅能判别对象类型,不能判别原始类型:
- 内置对象类型
[] instanceof Object
→ true[] instanceof Array
→ true[] instanceof Date
→ false - 自定义对象类型及其继承关系
1
2
3
4
5
6
7
8
9function Person(){}
function Student(){}
var p = new Person()
Student.prototype = p // Student原型继承p,Student.prototype._proto_ = p.prototype
var s = new Student()
console.log(s instanceof Student) // 输出true
console.log(s instanceof Person) // 输出true
Student.prototype = {}
console.log(s instanceof Student) // 输出false
instanceof的模拟函数:
1 | function _instanceof(A, B) { |
因此:
1) Object instanceof Object
→ true
第一个Object的原型链:
Object → (Object._proto_) → Function.prototype → (Function.prototype._proto_) → Object.prototype
第二个Object的原型:Object → Object.prototype
2) Function instanceof Function
→ true
第一个Function的原型链:
Function => (Function._proto_) => Function.prototype
第二个Function的原型:Function => Function.prototype
3) console.log(Function instanceof Object)
→ true
Function的原型链:
Function => (Function._proto_) => Function.prototype => (Function.prototype._proto_) => Object.prototype
Object的原型:Object => Object.prototypefunction Person() {}
4) console.log(Person instanceof Function)
→ true
Person的原型链:Person => (Person._proto_) => Function.prototype
Function的原型:Function => Function.prototype
5) console.log(String instanceof String)
→ false
第一个String的原型链:
String => (String._proto_) => Function.prototype => (Function.prototype._proto_) => Object.prototype
第二个String的原型:String => String.prototype
6) console.log(Boolean instanceof Boolean)
→ false
同理String
7) console.log(Person instanceof Person)
→ false
第一个Person的原型链:
Person => (Person._proto_) => Function.prototype => (Function.prototype._proto_) => Object.prototype
第二个Person的原型:Person => Person.prototype
3. Object.prototype.toString.call(检测对象)
检测对象 | 检测结果 | ||
---|---|---|---|
undefined | “[object Undefined]” | ||
null | “[object Null]” | ||
true | “[object Boolean]” | ||
123 | “[object Number]” | ||
NaN | “[object Number]” | ||
“123” | “[object String]” | ||
[] | “[object Array]” | ||
{} | “[object Object]” | ||
function(x){f(x);} | “[object Function]” | ||
* 对于没有重写toString方法的自定义对象类型,返回均为[object Object] ,其构造函数返回[object Function] ,如: |
|||
|
4. (检测对象).constructor
具体操作:(检测对象).constructor.toString().match(/function\s*([^(]*)/)[1]
(匹配正则没懂)(检测对象).constructor.toString().split(/ |\(/)[1]
基本可以判别所有类型:
1 | function Person() {} |