js引用类型引起的问题
6种基本类型
- string
- number
- bool
- null
- undefined
- symbol
通俗易懂的话来讲,js的基本类型使用用来存储值得,它们分配大小是有限度 在定义基本类型变量的时候它们的内存都被分配完成,
- 数字有最大值和最小值
- null undefined的是固定的值
- bool 值为 true和false
string
、number
、boolean
和 symbol
这四种类型统称为原始类型(Primitive) ,表示不能再细分下去的基本类型;symbol
表示独一无二的值,通过 Symbol
函数调用生成,由于生成的 symbol
值为原始类型,所以 Symbol
函数不能使用 new
调用;null
和 undefined
通常被认为是特殊值,这两种类型的值唯一,就是其本身。
引用类型
-
对象
-
数组
-
函数
和基本类型区分开来。对象在逻辑上是属性的无序集合或者有序集合,是存放各种值的容器。对象值存储的是引用地址,所以和基本类型值不可变的特性不同,对象值是可变的。
包装对象
我们知道对象拥有属性和方法。但比如字符串这种基本类型值不属于对象为什么还拥有属性和方法呢?实际上在引用字符串的属性或方法时,会通过调用 new String()
的方式转换成对象,该对象继承了字符串的方法来处理属性的引用,一旦引用结束,便会销毁这个临时对象,这就是包装对象的概念。
不仅仅只是字符串有包装对象的概念,数字和布尔值也有相对应的 new Number()
和 new Boolean()
包装对象。null
和 undefined
没有包装对象,访问它们的属性会报类型错误。
字符串、数字和布尔值通过构造函数显式生成的包装对象,既然属于对象,和基本类型的值必然是有区别的,这点可以通过 typeof
检测出来。
typeof 'seymoe' // 'string'
typeof new String('seymoe') // 'object'
复制代码
数据类型的判断
-
typeof
-
instanceof
-
Object.prototype.toString()
typeof
`typeof` 操作符来判断一个值属于哪种基本类型,返回值是一个string,对null判断有误,认为null是个空指针typeof 'seymoe' // 'string' typeof true // 'boolean' typeof 10 // 'number' typeof Symbol() // 'symbol' typeof null // 'object' 无法判定是否为 null typeof undefined // 'undefined' 复制代码
如果使用
typeof
操作符对对象类型及其子类型,譬如函数(可调用对象)、数组(有序索引对象)等进行判定,则除了函数都会得到object
的结果。typeof {} // 'object' typeof [] // 'object' typeof(() => {})// 'function' 复制代码
由于无法得知一个值到底是数组还是普通对象,显然通过
typeof
判断具体的对象子类型远远不够。instanceof
通过 `instanceof` 操作符也可以对对象类型链上的构造函数进行判定,其原理就是测试构造函数的 `prototype` 是否出现在被检测对象的原型链上。 ``` [] instanceof Array // true ({}) instanceof Object // true (()=>{}) instanceof Function // true ```注意:
instanceof
也不是万能的。其原理就是测试构造函数var a={} a.__proto__=[] a instanceof Array //true a instanceof Object //true 复制代码
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]' 复制代码
数据类型转换
ToPrimitive
JavaScript 对象转换到基本类型值时,会使用 ToPrimitive 算法,这是一个内部算法,是编程语言在内部执行时遵循的一套规则。ToPrimitive 算法在执行时,会被传递一个参数 hint
,表示这是一个什么类型的运算(也可以叫运算的期望值),根据这个 hint
参数,ToPrimitive 算法来决定内部的执行逻辑。
hint
参数的取值只能是下列 3 者之一:
string
number
default
转换算法
当对象与到基本类型值发生转换时,会按照下面的逻辑调用对象上的方法: **为了进行转换,JavaScript 会尝试查找并调用三个对象方法:**-
调用
obj[Symbol.toPrimitive](hint)
- 带有符号键Symbol.toPrimitive
(系统符号)的方法,如果存在这样的方法, -
否则如果提示是
"string"
- 尝试
obj.toString()
和obj.valueOf()
,无论存在什么。
- 尝试
-
否则,如果提示是
"number"
或"default"
- 尝试
obj.valueOf()
和obj.toString()
,无论存在什么。
- 尝试
确定 hint
我们提到了 ToPrimitive 算法中用到的 hint
参数,那怎样确定一次运算场景下的 hint
取值是什么呢?很简单----新建一个对象,打印各个运算场景下的 hint
值:
let obj = {
name: "John",
money: 1000,
[Symbol.toPrimitive](hint) {
console.log(`hint: ${hint}`);
}
};
alert(obj) // hint: string
+obj // hint: number
obj + 500 // hint: default
// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
var obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
[Symbol.toPrimitive](hint) {
if (hint == "number") {
return 10;
}
if (hint == "string") {
return "hello";
}
return true;
}
};
console.log(+obj2); // 10 -- hint 参数值是 "number"
console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
console.log(obj2 + ""); // "true" -- hint 参数值是 "default"
复制代码
## Symbol.toPrimitive 和 toString/valueOf 方法
并不要求 `Symbol.toPrimitive` 和 `toString/valueOf` 方法必须返回 `hint` 参数值所暗示的类型值。但要注意下面两点:
Symbol.toPrimitive
和toString
方法的返回值必须是基本类型值。valueOf
方法除了可以返回基本类型值,也可以返回其他类型值。
当我们创建一个普通对象时({}
或 new Object()
的方式等),对象上是不具备 [Symbol.toPrimitive]
(方法)属性的。所以,对于普通对象的到基本类型值的运算,一般按照具体场景:
hint
值为"string"
时,先调用toString
,toString
如果返回一个基本类型值了,则返回、终止运算;否则接着调用valueOf
方法。- 否则,先调用
valueOf
,valueOf
如果返回一个基本类型值了,则返回、终止运算;否则接着调用toString
方法。
- 点赞
- 收藏
- 关注作者
评论(0)