JavaScript面试 - 数据类型篇

众所周知 JavaScript(一下简称 Js) 是一门弱类型语言,变量的类型不够明确,不一样类型之间能够相互赋值。
Js 的数据类型能够分为两大类:
\color{blue}{一、基础数据类型}
\color{blue}{二、引用数据类型}es6

一、基础数据类型

基础数据类型包含如下 \color{red}{6} 中:数组

  • Number
  • String
  • Boolean
  • undefined
  • null
  • Symbol (es6 新增的一种基础数据类型)

1-一、Number

1-1-一、声明的几种方式:

// 字面量的形式声明
var num = 23
console.log(num) // 23

// 实例化的形式声明
var num = new Number(23)
console.log(num) // 23

复制代码

1-1-二、Number 类型包含了 int、浮点数、科学记数法、八进制数和十六进制数及特殊的 Number 值

1-1-2-一、int

var num = 23
复制代码

1-1-2-二、浮点数

var num = 23.5
复制代码

1-1-2-三、科学记数法 E/e

var num = 1.5e12 // 表示1.5乘以10的7次方
var num = 1.5-e12 // 表示1.5除以10的7次方
复制代码

1-1-2-四、八进制

已 0 开头,后面的数字为任意的 0-7bash

var num = 070 // 等于十进制的 56
复制代码

转换规则:7 x 8^1 + 7 x 8^0 = 56函数

1-1-2-五、十六进制

已 0x 开头,后面的数字为任意的 0-F (字母能够是大写的,也能够是小写的)测试

var num = 0x1f // 等于十进制的 31
复制代码

转换规则:1 x 16^1 + 15 x 16^0 = 31ui

\color{red}{提示:}尽管全部整数均可以表示为八进制或十六进制的字面量,但全部数学运算返回的都是十进制结果。编码

1-1-2-六、特殊的 Number 值

  • Number.MAX_VALUE(Infinity) 和 Number.MIN_VALUE(-Infinity) 无穷大 和 无穷小 (能够对任何数调用 isFinite() 方法,以确保该数不是无穷大)
  • NaN 表示非数(Not a Number)。通常说来,这种状况发生在类型(String、Boolean 等)转换失败时。\color{red}{NaN 的另外一个奇特之处在于,它与自身不相等。}
console.log(NaN == NaN) // false
console.log(NaN === NaN) // false
复制代码

\color{red}{因此在判断是否是 NaN 的时候,推荐使用 isNaN()}

console.log(isNaN(NaN)) // true
console.log(isNaN(6)) // false
复制代码

1-二、String

1-2-三、声明方式

// 字面量的形式声明
var str = 'hello'
console.log(str) // hello

// 实例化的形式声明
var str = new String("hello")
console.log(str) // hello
复制代码

由上能够得出: \color{red}{在 Js 中咱们能够经过双引号,单引号来声明字符串,可是自身不能包裹自身(双引号不能包含双引号)}

1-三、Boolean

// 字面量的形式声明
var flag = false
console.log(flag) // false

// 实例化的形式声明
var flag = new Boolean(false)
console.log(flag) // false
复制代码

注意:\color{red}{只有两个值 true 和 false}spa

1-四、undefined

Undefined 类型只有一个值,即 undefined。\color{red}{当声明的变量未初始化时,该变量的默认值是 undefined。}3d

1-4-一、声明

var num
console.log(num)
复制代码

1-4-二、另外几种值为 undefined 的状况

  • 经过点语法访问的时候(对象属性)
  • 经过下标访问的时候(数组)
  • 不指定函数的返回值时

\color{red}{注意:}

var oTemp;

alert(typeof oTemp);  //输出 "undefined"
alert(typeof oTemp2);  //输出 "undefined"
复制代码

前面的代码对两个变量输出的都是 "undefined",即便只有变量 oTemp2 从未被声明过。若是对 oTemp2 使用除 typeof 以外的其余运算符的话,会引发错误,由于其余运算符只能用于已声明的变量上。
复制代码

1-五、null

null 类型只有一个值,即 null。指针

console.log(null == undefined) // true
console.log(null === undefined) // false

console.log(null == null) // true
console.log(null == null) // true
复制代码

\color{red}{null\ 自身跟自身相等,undefined\ 类型是\ null\ 的子类}

1-五、Symbol

Symbol 是 es6 新增的一种基础数据类型,是用来描述一个\color{red}{惟一性}的值。 Symbol(query: any): symbol query 对当前 Symbol 的描述,便于代码的阅读

1-5-一、声明方式

var symbol1 = Symbol('symbol')
var symbol2 = Symbol('symbol')

console.log(symbol1 === symbol2) // false
console.log(symbol1 === symbol2) // false
复制代码

1-5-二、用处

  • 能够用来声明一个常量
  • 能够用作对象的属性,可是不能被for-in, Object.keys()等访问到,也就是不可枚举的
  • 使用Symbol定义类的私有属性/方法

二、引用数据类型

引用数据类型包含如下 \color{red}{4} 中:

  • Object 对象
  • String 对象
  • Boolean 对象
  • Number 对象

以上对象的详细解析请参考 w3school

三、如何判断基础数据类型与引用数据类型之间

3-一、基础数据类型能够经过 typeof 来判断

var num = 12
console.log(typeof num) // number

var str = 'hello'
console.log(typeof str) // string

var flag = true
console.log(typeof flag) // boolean

var un
console.log(typeof un) // undefined

var nul = null
console.log(typeof nul) // object

var fun = function () {}
console.log(typeof fun) // function

var obj = new Object()
console.log(typeof obj) // object

var arr = [1, 2]
console.log(typeof obj) // object
复制代码

由上可知:\color{red}{ typeof 除了 null 之外其它的基本数据类型均可以判断,还产生了一种新的数据类型 function }

3-二、引用数据类型能够经过 instanceof 来判断 (实现原理是经过原型链)

var obj = new Object()
console.log(obj instanceof Object) // true

var str = new String('hello')
console.log(str instanceof String) // true

var arr = [1, 2]
console.log(arr instanceof Array) // true

var num = 1
console.log(num instanceof Number) // false
复制代码

总结:\color{red}{ typeof、instanceof 都不能准确的判断出具体的类型 }

四、基础数据类型与引用数据类型之间的区别

4-一、 基础数据类型与引用数据类型之间的区别主要体如今在内存中的存储。

咱们先来看一个例子,思考一下答案是什么

var num1 = 10
var num2 = num1

num2 = 20
console.log(num1, num2)

var person1 = {name: 'Tom'}
var person2 = person1

person2.name = "Kail"
console.log(person1, person2)
复制代码

答案:

10 20
{name: 'Kail'} {name: 'Kail'}

能够看出 num1 不会受到 num2 的影响,person1 会受到 person2 的影响。
复制代码

总结:\color{red}{引用数据类型在内存中的栈中存储的是地址(指针),基础数据类型存储的是值。因此在用引用数据类型直接赋值时,会直接影响的源数据。}

4-二、浅拷贝、深拷贝

浅拷贝、深拷贝的出现就是为了解决引用数据类型赋值时,产生相互影响的问题
复制代码

4-2-一、浅拷贝

浅拷贝\color{red}{只能修复第一层属性的值不为引用数据类型的属性,}仍是不能完全解决多层引用数据类型之间的嵌套。

var person1 = {name: 'Tom'}
var person2 = Object.assign({}, person1)

person2.name = "Kail"
console.log(person1, person2) // {name: "Tom"} {name: "Kail"}


var person1 = {targe: {name: 'Tom'}}
var person2 = Object.assign({}, person1)

person2.targe.name = "Kail"
console.log(person1, person2) // {targe: {name: 'Kail'}} {targe: {name: 'Kail'}}
复制代码

4-2-二、深拷贝

深拷贝跟层级无关

var person1 = {name: 'Tom'}
var person2 = JSON.parse(JSON.stringify(person1))

person2.name = "Kail"
console.log(person1, person2) // {name: "Tom"} {name: "Kail"}


var person1 = {targe: {name: 'Tom'}}
var person2 = JSON.parse(JSON.stringify(person1))

person2.targe.name = "Kail"
console.log(person1, person2) // {targe: {name: 'Tom'}} {targe: {name: 'Kail'}}
复制代码

五、类型之间的转换

5-一、 + (字符串链接符,加号运算符)只要有一边为字符串或者为引用数据类型时另一边就必须转换为字符串才能够作运算;只有两边都是纯数字时才作加法

var log = console.log

log(1 + 2)          // 3
log(1 + '2')        // '12'

log(1 + true)       // 2
log('1' + true)     // '1true'

log('1' + undefined)  // '1undefined'
log(1 + undefined)  // NaN

log('1' + null)  // '1null'
log(1 + null)  // 1

log(1 + [])         // '1'
log(1 + [2])        // '12'
log(1 + [2, 3])     // '12,3'
log(1 + [{count: 2}]) // '1[object Object]'
log(1 + [{count: 2}, 2, true]) // '1[object Object],2,true'

log(1 + {})         // '1[object Object]'
log(1 + {count: 2}) // '1[object Object]'
复制代码

分析:

一、undefined 转换成数字时为 NaN 
二、null 转换成数字时为 0
三、空数组转换为空字符串
四、非空数组转换为字符串,按照每一个元素来转换成字符串,而后将其结果以逗号的形式拼接起来
五、对象转换成字符串都为 '[object Object]'
复制代码

5-二、 算术运算符(除 + 以外),都会将两边转换成数字来运算,

var log = console.log

log(2 * 2)          // 4
log(2 * '2')        // 4
log('2' * '2')      // 4
log(2 * null)       // 0
log(2 * undefined)  // NaN
log(2 * [1])         // 2
log(2 * [1, 2])     // NaN
log(2 * {a: 1})     // NaN

log(2 / 2)          // 1
log(2 / '2')        // 1
log(2 / null)       // Infinity
log(2 / undefined)  // NaN
log(2 / [1])         // 2
log(2 / [1, 2])     // NaN
log(2 / {a: 1})     // NaN
复制代码

5-三、 比较运算符,都会将两边转换成数字来运算,(当两边为字符串时除外,此时会利用字符的 Unicode 编码来比较大小),特殊状况(以下)

log(2 > 2)          // false
log(2 > '1')        // true
log(2 > null)       // true
log(2 > [1])        // true
log(2 > {a: 1})     // false
log('a' > 2)      // false
log('abc' < 'b')    // true

// 特殊状况
log(undefined == undefined)  // true
log(undefined === undefined) // true

log(null == null)        // true
log(null === null)       // true

log(undefined == null)   // true
log(undefined === null)  // false

log(NaN == NaN)          // false
log(NaN === NaN)         // false
复制代码

5-四、 逻辑非隐式转换与关系运算符隐式转换搞混淆

log([] == 0)    // true     [].valueOf().toString = '' Number('') = 0
log(![] == 0)   // true     ![] = false Number(false) = 0    
log([] == [])   // false    地址不同
log(![] == [])  // true     ![] = false Number(false) = 0    [].valueOf().toString = '' Number('') = 0
log(!{} == {})  // false    !{} = false Number(false) = 0    {}.valueOf().toString = '[object Object]' Number('[object Object]') = NaN
log({} == {})   // false    地址不同
复制代码

5-四、类型转换总结表

type Number String Boolean
Number 原值转换 原值转换 1: 0-> false -0 -> false
2: 其它数值都为true
String 1: 所有由数字组成的字符串,正常转换;
2: 空字符串为0;
3: 其它为NaN
原值转换 1:空字符串为false;
2: 其它为true
Boolean false -> 0 true -> 1 原值转换
null 0 '' false
undefined NaN 原值转换 false
Object NaN '[object Object]' true
Array 1:[] 转换为 0([].valueOf().toString() = '' Number('') = 0)
2: 只有一个元素时,就按这个元素的类型转换成 Number([undefined] 除外,转换为 0)
3: 其它状况为 NaN
将每一个元素转换成字符串以逗号的形式拼接 true
function NaN 将函数直接变成字符串输出 true
Symbol var b = Symbol('测试类型转换')
Number(b)
Uncaught TypeError: Cannot convert a Symbol value to a number
var b = Symbol('测试类型转换')
String(b)
"Symbol(测试类型转换)"
true

【随手笔记,感谢阅读,不对之处请指教,谢谢】

相关文章
相关标签/搜索