考查点
- 分类
- 判断数据类型
- 数据类型转化(+-*/、比较运算)
分类
类型
** 基本数据类型(6种) **
- boolean
- number
- string
- null
- undefined
- symbol
** 引用数据类型(3种) **
- object
- array
- function
考点
undefined和null的区别
undefiend是声明了变量未赋值,null是声明了变量且赋值为null
关于number中的特殊值NaN
详见 判断数据类型 部分
string类型为什么会有length属性
一般来说,基本数据类型(值类型)是不存在方法和属性的。但使用string类型的属性或方法时,Js引擎会用包装类String()自动创建一个引用类型对象,在使用完后销毁。
关于symbol
symbol类型用于表示独一无二的值,是对象属性名的一种类型。
在有symbol之前,对象属性名的类型都是string。例如:
const obj = {a:1}
console.log(obj.a) // 1
console.log(obj['a']) // 1
// obj '.' 之后的属性名a 等价于obj '[]' 中的字符串'a'
// 对象点运算符之后的属性名类型为string
对象属性名类型为string时,为对象添加新属性时可能会有重名冲突,而symbol就是用来解决这种冲突,并提高代码的可维护性的。
// eg1
// symbol变量只能以 对象[symbol变量] 这种方式使用
// 每一个symbol变量值都是唯一的,不会冲突覆盖
let s1 = Symbol()
const obj = {
[s1](){console.log('hello')}
[Symbol()](){},
[Symbol()](){}
}
obj[s1]() // hello
console.log(obj) // {Symbol():f, Symbol(): f, Symbol(): f}
// eg2
// 在常量对象中使用symbol,结合switch case消除魔术字符串
const COLOR = {
RED: Symbol('red'),
GREEN: Symbol('green')
}
function getComplement(color) {
switch (color) {
case COLOR.RED:
console.log(COLOR.RED.description) // red
return COLOR_GREEN
case COLOR.GREEN:
console.log(COLOR.GREEN.description) // green
return COLOR_RED
default:
throw new Error('Undefined color');
}
}
// eg3
// symbol类型的属性无法被Object.keys()、Object.getOwnPropertyNames()、for-in、for-of获取,所以可以用来定义私有
let s3 = symbol('s3')
const obj = {
a: 0
b: 1
[s3]: 2
}
console.log(Object.keys(obj)) // ['a', 'b']
console.log(Object.getOwnPropertyNames(obj)) // ['a', 'b']
console.log(Object.getOwnPropertySymbols(obj)) // Symbol('s3')
// eg4
// Symbol.for登记全局特性,通过它可以取到同一个Symbol
let s4 = Symbol('str')
let s5 = Symbol('str')
console.log(s4 == s5) // false
let s6 = Symbol.for('str')
let s7 = Symbol.for('str')
console.log(s6 == s7) // true
// eg5
// Symbol.toPrimitive用于数据类型转化(详见 数据类型转化 部分)
判断数据类型
通用判断方法
typeof
根据变量存储值的机器码判断变量类型。
无法区分:null、array。(typeof会将这两种类型视为object)
能区分:boolean、number、string、undefined、symbol、object、function。
console.log(typeof Boolean) // function
console.log(typeof Boolean()) // boolean
console.log(typeof Number) // function
console.log(typeof Number()) // number
console.log(typeof String) // function
console.log(typeof String()) // string
console.log(typeof undefined) // undefined
console.log(typeof Symbol) // function
console.log(typeof Symbol()) // symbol
console.log(typeof Object) // function
console.log(typeof Object()) // object
console.log(typeof Function) // function
console.log(typeof Function()) // function
console.log(typeof null) // object
console.log(typeof Array) // function
console.log(typeof Array()) // object
Object.prototype.toString.call()
对于基本数据类型,会将自动用对应包装类将其转化为引用类型,然后调用对应方法
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call(1)) // [object Number]
console.log(Object.prototype.toString.call('123')) // [object String]
console.log(Object.prototype.toString.call(null)) // [object Null]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(Symbol())) // [object Symbol]
对于引用数据类型
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call(()=>{})) [object Function]
console.log({}.toString) // [object Object]
console.log([].toString) // ""
console.log(function(){}.toString()) // function(){}
Object.prototype.toString.call()方法和对象自身的toString()方法得到的结果不同,是因为Array和Function是Object的实例,且Array和Function在自己的原型上重写了toString方法,所以返回结果不一样。
判断特定类型
判断引用类型 instanceof
用法: 对象(引用类型实例) instanceof 构造函数
通过在对象的原型链上查找是否有某构造函数的原型来判断类型。
console.log('123' instanceof String) // false '123'不是对象,必然是false
console.log(new String('123') instanceof String) // true
console.log([] instanceof Array) // true
console.log([] instanceof object) // true
console.log({} instanceof Object) // true
手写instanceof
function(obj, func){
while(true){
if(!obj){
return false
}
if(obj.__proto__ === func.prototype){
return true
}
obj = obj.__proto__
}
}
判断数组类型 Array.isArray()
console.log(Array.isArray([])) // true
console.log(Array.isArray({})) // false
判断NaN
NaN表示不是一个数字。它可以理解为一片不确定的范围,所以它和任何其他确定值的比较结果都是false。
判断是否为NaN有两种方法:isNaN() 和 NaN != NaN
** isNaN() **
console.log(isNaN(NaN)) // true
console.log(isNaN(!NaN)) // false
// 非数值参数会被Number()自动转化后再判断
// 转化规则详见 数据类型转化 部分
console.log(Number([])) // 0
console.log(isNaN([])) // false
console.log(Number({})) // NaN
console.log(isNaN({})) // true
** NaN!=NaN **
NaN与任何值(包括其本身)比较结果都是false
// 推荐这种方法
let x = 0/0
if(x!=x){
console.log('x is NaN')
}
数据类型转化
转化方法分为显式转化和隐式转化。不管什么用方法转化,一般都会把数据转成boolean、number、string这三种类型。
显示转化
转成boolean
// 只有这几项为假值,其它都为真
// 空数组,空对象也转为真
console.log(Boolean(false)) // false
console.log(Boolean(0)) // false
console.log(Boolean('')) // false
console.log(Boolean(null)) // false
console.log(Boolean(undefined)) // false
console.log(Boolean(NaN)) // false
转成number
Number()
// 转boolean
console.log(Number(true)) // 1
console.log(Number(false)) // 0
// 转null
console.log(Number(null)) // 0
// 转undefined
console.log(Number(undefined)) // 0
// 转字符串
////1.字符串中只包含数字,则转化为十进制数字(忽略前导0)
console.log(Number('9')) // 9
console.log(Number('09')) // 9
////2.浮点格式字符串转化为浮点数
console.log(Number('3.14')) // 3.14
////3.空字符串转化为0
console.log(Number('')) // 0
////4.不属于以上三种情况,转化为NaN
console.log(Number('啊啊啊')) // NaN
// 转引用对象
////1.先调用引用对象的valueOf()方法,再根据前面的结果转化方法返回值
////2.若1过程的最终值为NaN,则调用toString()方法,再根据前面的结果转化方法返回值
console.log([1,2,3].valueOf()) // [1,2,3]
console.log([1,2,3].toString()) // 1,2,3
console.log(Number([1,2,3])) // NaN
console.log(Number([])) // 0
console.log({}.valueOf()) // {}
console.log({}.toString()) // [Object Object]
console.log(Number({})) // NaN
console.log(function(){}.valueOf()) // ƒ (){}
console.log(function(){}.toString()) // function(){}
console.log(Number(function(){})) // NaN
parseInt(str, radix)
// 忽略字符串前面的空格,直至找到第一个非空字符
// 如果第一个字符不是数字符号或者负号,返回NaN
// 如果第一个字符是数字,则继续解析直至字符串解析完毕或者遇到一个非数字符号为止
// 如果上步解析的结果以0开头,则将其当作八进制来解析;如果以x开头,则将其当作十六进制来解析
// 如果指定radix参数,则以radix为基数进行解
parseFloat()
// 规则与parseInt基本相同
// 字符串中第一个小数点符号是有效的
// 另外parseFloat会忽略所有前导0
// 如果字符串包含一个可解析为整数的数,则返回整数值而不是浮点数值。
转成string
除了undefined和null都有toString()方法
console.log([1,2,3].toString()) // 1,2,3
console.log(true.toString()) // true
console.log(false.toString()) // false
console.log({}.toString()) // [object objectname]
也可以用String()包装类来转化
console.log(String(null)) // null
console.log(String(undefined)) // undefined
隐式转化
isNaN()
// isNaN()函数对非number类型的参数会先调用Number()进行显示转化
// 规则同Number()显示转化
--、++、一元正负符号操作符
// 相当于Js引擎自动调用Number()对操作数进行转换,然后再对结果进行--\++等操作
+
// number类型 + number类型 = number类型
1 + 1 => 1
1 + NaN => NaN // NaN加任何数结果都为NaN
Infinity+(-Infinity) => NaN
// 非number类型相加 或者 number类型加非number类型
// 等价于 string类型 + string类型
// 此时会对操作数进行toString()显示转化
// 对于没有toString()方法的null和undefined来说
// null会被视为0,任何数加undefined结果为NaN
console.log(1 + null) // 1
console.log(1 + undefined) // NaN
// 注意 + 操作是从左到右进行的
1 + 2 + 'test' => 3 + 'test' => '3test'
* 、 / 、 - 、 %
// 自动调用number()对非number类型的操作数进行转化
// 规则遵循Number()的显示转化
! 、&& 、||
// 自动调用Boolean()对非boolean类型的操作数进行转化
// 规则遵循Boolean()的显示转化
<, >, <=, >=
// 但凡有一个操作数是number类型,那就等价于number类型与number类型比较
// 所有的boolean类型操作数都会被转化成number类型
// 若两个操作数是string类型,那进行字符编码比较
// 引用类型调用valueOf()方法(若无该方法则调用toString()方法),再按前面规则进行比较
// NaN值和任何值(包括其本身)比较其结果都是false
==
// 规则同<, >, <=, >=
// 但对于两个引用类型,==比较的是引用地址是否相等
// console.log(null === undefined) // true