最近在看js的一些比较基础的东西,自己记录一下自己觉得比较容易遗忘或者混淆的知识点,方便自己温习,不足的地方还望大家支出更正,感谢!!!
这节我们回顾下对象到基本数据类型的转换。
我们先看一道有趣的题
(a == 1 && a == 2 && a == 3)
如何让这个等式成立?
进入正题
对象到基本类型的转换无非就三种 1.对象转string类型 2.对象转number类型 3.对象转boolean类型,又因为所有的对象在布尔上下文中均为 true
所以基本就是前两种类型的转换
为了进行转换,JavaScript 尝试查找并调用三个对象方法:
- 调用
obj[Symbol.toPrimitive](hint)
—— 带有 symbol 键Symbol.toPrimitive
(系统 symbol)的方法,如果这个方法存在的话, - 否则,如果 hint 是
"string"
—— 尝试obj.toString()
和obj.valueOf()
,无论哪个存在。 - 否则,如果 hint 是
"number"
或"default"
—— 尝试obj.valueOf()
和obj.toString()
,无论哪个存在。
猛一看有点犯迷糊,toString()和valueOf()这两个方法我们有了解,但是【Symbole.toPrimitive】和【hint】有点上头 接下来我们一点点的来了解
【Symbole.toPrimitive】(现代方法)
首先 Symbole.toPrimitive 这是有一个名为 Symbol.toPrimitive
的内建 symbol,用来给转换方法命名
obj[Symbol.toPrimitive] = function(hint) {
// 返回一个原始值
// hint = "string"、"number" 和 "default" 中的一个
}
我们可以把 Symbole.toPrimitive 当做obj的一个方法,这个方法我们可以自己来实现,返回需要的基本类型,而这个函数的参数hint是固定的
只有三种:'string','number','default',
疑问?怎么没有boolean呢,
因为所有的对象在布尔上下文中均为 true
let user = {
name: "John",
money: 1000,
[Symbol.toPrimitive](hint) {
// hint = "string"、"number" 和 "default" 中的一个
return hint == "string" ? `{name: "${this.name}"}` : this.money;
}
};
// 转换演示:
alert(user); // hint: string -> {name: "John"}
alert(+user); // hint: number -> 1000
alert(user + 500); // hint: default -> 1500
当我们alert一个对象是,alert期望值是获得一个字符串,当获取到的是一个对象是会打印出 '[object Object]',当我们实现了 【Symbole.toPrimitive】方法,alert的时候会自动调用这个方法,而hint是一个'string'是因为alert期望获取string类型。
第二个alert,当我们进行
显示类型转换let num = Number(obj);
数据运算((除了二元加法))let n = +obj; // 一元加法
let delta = date1 - date2;
小于/大于的比较let greater = user1 > user2;
,当调用【Symbole.toPrimitive】方法hint都会得到'number'
第三个alert
在少数情况下发生,当运算符“不确定”期望值的类型时。例如,二元加法 +
可用于字符串(连接),也可以用于数字(相加),所以字符串和数字这两种类型都可以,当调用【Symbole.toPrimitive】方法hint都会得到'default'
[toString/valueOf](远古方法)
方法 toString
和 valueOf
来自上古时代,它们不是 symbol(那时候还没有 symbol 这个概念),而是“常规的”字符串命名的方法。它们提供了一种可选的“老派”的实现转换的方法。
如果没有 Symbol.toPrimitive
,那么 JavaScript 将尝试找到它们,并且按照下面的顺序进行尝试:
- 对于 “string” hint,
toString -> valueOf
。 - 其他情况,
valueOf -> toString
。
这些方法必须返回一个原始值。如果 toString
或 valueOf
返回了一个对象,那么返回值会被忽略
默认情况下,普通对象具有 toString
和 valueOf
方法:
toString
方法返回一个字符串"[object Object]"
。valueOf
方法返回对象自身。
let user = {name: "John"};
alert(user); // [object Object]
alert(user.valueOf() === user); // true
我们可以将上面【Symbol.toPrimitive】的例子使用使用 toString
和 valueOf
的组合实现
let user = {
name: "John",
money: 1000,
// 对于 hint="string"
toString() {
return `{name: "${this.name}"}`;
},
// 对于 hint="number" 或 "default"
valueOf() {
return this.money;
}
};
alert(user); // toString -> {name: "John"}
alert(+user); // valueOf -> 1000
alert(user + 500); // valueOf -> 1500
对于以上结果 上面有讲解toString和valueOf的执行顺序,这里再赘述一下 对于hint是string 优先调用toString 没有的话再调用valueOf 其他情况则相反
- 对于 “string” hint,
toString -> valueOf
。 - 其他情况,
valueOf -> toString
。
返回类型
Symbol.toPrimitive
必须 返回一个原始值,否则就会出现 error。
由于历史原因,如果 toString
或 valueOf
返回一个对象,则不会出现 error,但是这种值会被忽略(就像这种方法根本不存在)。这是因为在 JavaScript 语言发展初期,没有很好的 “error” 的概念。
obj
****(a == 1 && a == 2 && a == 3)
回到最初的趣味题,就可以使用类型转换来进行解答
var a = { value : 0 };
a[Symbol.toPrimitive] = function(hint) {
console.log(hint); // default
return this.value += 1;
}
console.log(a == 1 && a == 2 && a == 3); // true
var a = { value : 0 };
a.valueOf = function() {
return this.value += 1;
};
console.log(a == 1 && a == 2 && a == 3); // true
var a = { value : 0 };
a.toString = function() {
return this.value += 1;
};
console.log(a == 1 && a == 2 && a == 3); // true
素材资料来自 现代 JavaScript教程 ,感兴趣的各位可以移步观看。