# JavaScript 的数据类型

# 常见面试题

//类型转换相关问题
var bar=true;
console.log(bar+0);
console.log(bar+"xyz");
console.log(bar+true);
console.log(bar+false);
console.log('1'>bar);
console.log(1+'2'+false);
console.log('2' + ['koala',1]);

var obj1 = {
   a:1,
   b:2
}
console.log('2'+obj1)var obj2 = {
    toString:function(){
        return 'a'
    }
}
console.log('2'+obj2)

//输出结果  1 truexyz 2 1 false 12false 2koala,1 2[object Object] 2a

//作用域和NaN 这里不具体讲作用域,意在说明NaN
var b = 1
function outer() {
  var b = 2
  function inner() {
    b++
    console.log(b)
    var b = 3
  }
  inner()
}
outer()
//输出结果 NaN

问: javascript中有哪些数据类型?

JavaScript 中共有七种内置数据类型,包括基本类型和对象类型。

# 基本类型

基本类型分为以下六种:

  • string(字符串)
  • boolean(布尔值)
  • number(数字)
  • symbol(符号)
  • null(空值)
  • undefined(未定义)

注意:

  • 1.stringnumberbooleannull undefined 这五种类型统称为原始类型(Primitive),表示不能再细分下去的基本类型;

  • 2.symbolES6 中新增的数据类型,symbol 表示独一无二的值,通过 Symbol函数调用生成,由于生成的 symbol值为原始类型,所以Symbol 函数不能使用new 调用;

  • 3.nullundefined 通常被认为是特殊值,这两种类型的值唯一,就是其本身。

# 对象类型

对象类型也叫引用类型,array和function是对象的子类型。对象在逻辑上是属性的无序集合,是存放各种值的容器。

对象值存储的是引用地址,所以和基本类型值不可变的特性不同,对象值是可变的

# js 弱类型语言

问: 说说你对javascript是弱类型语言的理解?

JavaScript 是弱类型语言,而且JavaScript 声明变量的时候并没有预先确定的类型,变量的类型就是其值的类型,也就是说变量当前的类型由其值所决定,夸张点说上一秒种的String,下一秒可能就是个Number类型了,这个过程可能就进行了某些操作发生了强制类型转换。

# toString

Object.prototype.toString()

toString()方法返回一个表示该对象的字符串。

每个对象都有一个 toString() 方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。

这里先记住,valueOf() 和 toString()在特定的场合下会自行调用。

# valueOf

Object.prototype.valueOf()方法返回指定对象的原始值。

JavaScript调用 valueOf()方法用来把对象转换成原始类型的值(数值、字符串和布尔值)。但是我们很少需要自己调用此函数,valueOf 方法一般都会被 JavaScript 自动调用。

不同内置对象的valueOf实现:

  • String => 返回字符串值`
  • Number => 返回数字值`
  • Date => 返回一个数字,即时间值,字符串中内容是依赖于具体实现的
  • Boolean=> 返回Booleanthis
  • 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 转换为 0
  • undefined 转换为 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:

  • 1.undefined
  • 2.null
  • 3.-0
  • 4.0 或+0
  • 5.NaN
  • 6.''(空字符串)

假值以外的值都是真值。其中包括所有对象(包括空对象)的转换结果都是true,甚至连false对应的布尔对象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

# 什么时候自动转换为 Number

  • 有加法运算符,但是无String类型的时候,都会优先转换为Number类型
true + 0 // 1
true + true // 2
true + false //1

  • 除了加法运算符,其他运算符都会把运算自动转成数值。
javascript '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的例子

  • 1.如果x,y均为number,直接比较没什么可解释的了
1 == 2 //false

  • 2.如果存在对象,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

  • 3.存在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

# js 中的数据类型判断

问 : 如何判断数据类型?怎么判断一个值到底是数组类型还是对象?

# 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'

上面代码的输出结果可以看出,

  • 1.null 的判定有误差,得到的结果,如果使用 typeof,null得到的结果是object

  • 2.操作符对对象类型及其子类型,例如函数(可调用对象)、数组(有序索引对象)等进行判定,则除了函数都会得到 object 的结果。

  • 3.综上可以看出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.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]]
  • 传入原始类型却能够判定出结果是因为对值进行了包装
  • nullundefined 能够输出结果是内部实现有做处理

# 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