# js 中的基本类型和引用类型
# 内置类型
JS 中七种内置类型(null,undefined,boolean,number,string,symbol,object)又分为两大类型
简记(nubnsso)
# 两大类型:
- 基本类型:
null
,undefined
,boolean
,number
,string
,symbol
- 引用类型 Object:
Array
,Function
,Date
,RegExp
等
# 存放位置:
- 基本数据类型:基本类型值在内存中占据固定大小,直接存储在栈内存中的数据
- 引用数据类型:引用类型在栈中存储了指针,这个指针指向堆内存中的地址,真实的数据存放在堆内存里。
# 值的可变性:
- 基本数据类型: 值不可变,javascript 中的原始值(undefined、null、布尔值、数字和字符串)是不可更改的
- 引用数据类型:引用类型是可以直接改变其值的
//基本数据类型
var str = 'abc'
console.log((str[1] = 'f')) // f
console.log(str) // abc
//引用数据类型
var a = [1, 2, 3]
a[1] = 5
console.log(a[1]) // 5
2
3
4
5
6
7
8
9
# 比较:
- 基本数据类型: 基本类型的比较是值的比较,只要它们的值相等就认为他们是相等的
- 引用数据类型: 引用数据类型的比较是**引用的比较,**看其的引用是否指向同一个对象
//基本数据类型
var a = 1
var b = 1
console.log(a === b) //true
//引用数据类型
var a = [1, 2, 3]
var b = [1, 2, 3]
console.log(a === b) // false
//虽然变量 a 和变量 b 都是表示一个内容为 1,2,3 的数组,
//但是其在内存中的位置不一样,也就是说变量 a 和变量 b 指向的不是同一个对象,所以他们是不相等的
2
3
4
5
6
7
8
9
10
11
# Typeof
typeof
对于基本类型,除了 null
都可以显示正确的类型,对于 null
来说,虽然它是基本类型,但是会显示 object
,这是一个存在很久了的 Bug, 这与 JavaScript 的历史有关,null 被设计成可以自动转为 0
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b 没有声明,但是还会显示 undefined
typeof null // 'object'
// typeof` 对于对象,除了函数都会显示 `object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
2
3
4
5
6
7
8
9
10
11
12
获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)
。这样我们就可以获得类似 [object Type]
的字符串。
Object.prototype.toString.call(22) //"[object Number]"
Object.prototype.toString.call('22') //"[object String]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(a) //"[object Undefined]"
Object.prototype.toString.call(true) //"[object Boolean]"
Object.prototype.toString.call({ a: 1 }) //"[object Object]"
2
3
4
5
6
7
8
9
10
11
12
typeof 的安全防范机制
检查 DEBUG 变量是否已被声明
if (DEBUG) {
console.log('Debugging is starting')
}
// 报错 ReferenceError 错误
if (typeof DEBUG !== 'undefined') {
console.log('Debugging is starting')
}
2
3
4
5
6
7
8
# 基本类型
# null
- null 类型也只有一个值,就是 null,它的语义表示空值
- null 是 JavaScript 关键字
常见问题:null 和 undefined 的区别?
null 表示"没有对象",即该处不应该有值。典型用法是:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype)
// null
2
undefined 表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于 undefined。(2)调用函数时,应该提供的参数没有提供,该参数等于 undefined。(3)对象没有赋值的属性,该属性的值为 undefined。(4)函数没有返回值时,默认返回 undefined。
//变量被声明了,但没有赋值时,就等于undefined。
var i
i // undefined
//调用函数时,应该提供的参数没有提供,该参数等于undefined。
function f(x) {
console.log(x)
}
f() // undefined
//对象没有赋值的属性,该属性的值为undefined。
var o = new Object()
o.p // undefined
//函数没有返回值时,默认返回undefined。
var x = f()
x // undefined
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# undefined
- undefined 类型表示未定义,它的类型只有一个值,就是 undefined。
- 任何变量在赋值前是 undefined 类型、值为 undefined
- undefined 是一个变量,而并非是一个关键字
常见问题:为什么有的编程规范要求用 void 0 代替 undefined?
因为 JavaScript 的代码 undefined 是一个变量,而并非是一个关键字,这是 JavaScript 语言公认的设计失误之一,所以,我们为了避免无意中被篡改,建议使用 void 0 来获取 undefined 值,void 后面随便跟上一个变量,组成表达式,返回就是 undefined
let a
a === undefined //true
a //undefined
void 0 //undefined void 后面随便跟上一个组成表达式返回就是 undefined
a === void 0 //true
2
3
4
5
# boolean
Boolean 类型有两个值, true 和 false
# number
JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则,但是 JavaScript 为了表达几个额外的语言场景(比如不让除以 0 出错,而引入了无穷大的概念),规定了几个例外情况:
- NaN,占用了 9007199254740990,这原本是符合 IEEE 规则的数字;
- Infinity,无穷大;
- -Infinity,负无穷大。
常见问题:0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?
这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值:
console.log(Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON)
检查等式左右两边差的绝对值是否小于最小精度,才是正确的比较浮点数的方法。这段代码结果就是 true 了。
# string
string 常见问题:
# symbol
Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑。
//创建
var mySymbol = Symbol('my symbol')
2
# 引用类型
# Object
Object 表示对象的意思,它是一切有形和无形物体的总称。在 JavaScript 中,对象的定义是“属性的集合”。
属性分为数据属性和访问器属性,二者都是 key-value 结构,key 可以是字符串或者 Symbol 类型
# 现象:类型转换
# 四则运算符
加法
- 运算中其中一方为字符串,那么就会把另一方也转换为字符串
- 如果任何一方都不是字符串或者数字,那么会将它们都转换为数字或者字符串(具体转换参照对象转原始类型)
其他运算符
- 只要其中一方是数字,那么另一方就会被转为数字
1 + '1' // '11'
true + true // 2
4 + [1, 2, 3] // "41,2,3"
4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN
2
3
4
5
6
7
# ==
操作符
JavaScript 中的“ == ”运算,因为试图实现跨类型的比较,它的规则复杂到几乎没人可以记住, 它属于设计失误,并非语言中有价值的部分,很多实践中推荐禁止使用“ ==”,而要求程序员进行显式地类型转换后,用 === 比较
# 比较运算符
- 如果是对象,则转换为原始类型再比较值
- 如果是字符串,就通过
unicode
字符索引来比较
'10'.charCodeAt() //49
'厉害'.charCodeAt() //21385
'10' < '厉害' //true
'10' > '厉害' //false
2
3
4
# 对象转基本类型
对象在转换类型的时候,会调用内置的[[ToPrimitive]]
函数
转换流程:
- 如果已经是原始类型了,就不需要转换了(因为可以重写
Symbol.toPrimitive
) - 有
Symbol.toPrimitive
方法时则只调用该方法,优先级最高 - 如果对象需要转换为字符串类型,则直接调用
toString
方法,转换为基础类型的话就返回转换的值 - 如果不是字符串类型,则先调用
valueOf
方法,结果不是基础类型的话再调用toString
方法 - 如果以上处理后,都没有返回原始类型,就会报错
var a = {
valueOf() {
return 0
},
toString() {
return '1'
},
[Symbol.toPrimitive]() {
return 2
}
}
var b = {
valueOf() {
return 0
},
toString() {
return '1'
}
}
console.log(`abc${b}`) // => 'abc1'
console.log(1 + a) // => 3
console.log('1' + a) // => '12'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 装箱转换
JS 引擎有意去模糊“对象”和“基本类型”之间的关系, 遇到"."时,JS 引擎会临时帮我们做一层“装箱转换”,这里就是 new String() 生成一个“临时对象”,这个临时对象是基本类型对应的包装类型。
装箱转换,正是把基本类型对象转换为对应的包装类型对象,它是类型转换中一种相当重要的种类
// Number
1
new Number(1)
// String
;('aaa')
new String('aaa')
// Boolean
true
new Boolean(true)
2
3
4
5
6
7
8
9
10
11
Symbol 不能 new,我们用特殊的方法把它 new 出来
Object(Symbol('aaa'))(
// 或者
function() {
return this
}
).call(Symbol('aaa'))
2
3
4
5
6
# 拆箱转换
JS 中拆箱转换是调用了对象的 toPrimitive 方法来拆箱,它会依次尝试使用valueOf
, toString
来转换,如果没有valueOf
, toString
方法,或者这 2 个方法转换出来的都是非基本类型,则报错
在线客服