js基础知识回顾(3)---对象到基本类型的转换

185 阅读2分钟

最近在看js的一些比较基础的东西,自己记录一下自己觉得比较容易遗忘或者混淆的知识点,方便自己温习,不足的地方还望大家支出更正,感谢!!!

这节我们回顾下对象到基本数据类型的转换。

我们先看一道有趣的题

    (a == 1 && a == 2 && a == 3)

如何让这个等式成立?

进入正题

对象到基本类型的转换无非就三种 1.对象转string类型 2.对象转number类型 3.对象转boolean类型,又因为所有的对象在布尔上下文中均为 true 所以基本就是前两种类型的转换

为了进行转换,JavaScript 尝试查找并调用三个对象方法:

  1. 调用 obj[Symbol.toPrimitive](hint) —— 带有 symbol 键 Symbol.toPrimitive(系统 symbol)的方法,如果这个方法存在的话,
  2. 否则,如果 hint 是 "string" —— 尝试 obj.toString() 和 obj.valueOf(),无论哪个存在。
  3. 否则,如果 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教程 ,感兴趣的各位可以移步观看。