一、问题引入
你知道执行以下三种情况,控制台会打印什么吗?
(1)情况一:方法的返回值为1
Array.prototype.toString = function () {
console.log('array-----调用toString方法')
return 1
}
Array.prototype.valueOf = function () {
console.log('array-----调用valueOf方法')
return 1
}
Function.prototype.toString = function () {
console.log('function-----调用toString方法')
return 1
}
Function.prototype.valueOf = function () {
console.log('function-----调用valueOf方法')
return 1
}
let arr = new Array()
let fn = function () {
console.log('函数内打印')
}
console.log(arr)
console.log(fn)
console.log('console.log-----' + arr)
console.log('console.log-----' + fn)
(2)情况二:方法无返回值
Array.prototype.toString = function () {
console.log('array-----调用toString方法')
}
Array.prototype.valueOf = function () {
console.log('array-----调用valueOf方法')
}
Function.prototype.toString = function () {
console.log('function-----调用toString方法')
}
Function.prototype.valueOf = function () {
console.log('function-----调用valueOf方法')
}
let arr = new Array()
let fn = function () {
console.log('函数内打印')
}
console.log(arr)
console.log(fn)
console.log('console.log-----' + arr)
console.log('console.log-----' + fn)
(3)情况三:方法返回值为一个匿名函数
Array.prototype.toString = function () {
console.log('array-----调用toString方法')
return function () {}
}
Array.prototype.valueOf = function () {
console.log('array-----调用valueOf方法')
return function () {}
}
Function.prototype.toString = function () {
console.log('function-----调用toString方法')
return function () {}
}
Function.prototype.valueOf = function () {
console.log('function-----调用valueOf方法')
return function () {}
}
let arr = new Array()
let fn = function () {
console.log('函数内打印')
}
console.log(arr)
console.log(fn)
console.log('console.log-----' + arr)
console.log('console.log-----' + fn)
控制台输出如下,你答对了吗?
控制台输出结果:
全对的大佬可以出门左转了,出现错误的同学请继续往下看~
二、具体情况分析
针对直接使用cosole.log打印单独的对象,打印语句一在三种情况下都发挥正常。但是往下看,打印语句二console.log(fn)
- 方法返回值为1:打印函数体,自动调用toString()
- 方法无返回值(undefined):打印函数体,自动调用toString()
- 方法返回匿名函数:打印函数体,自动调用toString()之后调用valueOf()
从上面的结果中我们猜测,当打印的内容为函数时,会在内部隐式调用toString(),如果toString()返回基本数据类型,则数据转换到此为止。如果返回对象数据类型,则在toString()之后还会调用valueOf()。
打印语句3和4:
- 方法返回值为1:自动调用valueOf(),打印valueOf()返回值
- 方法无返回值(undefined):自动调用valueOf(),打印valueOf()返回值
- 方法返回匿名函数:自动调用valueOf()之后调用toString(),报错
有报错最好~从报的错误开始入手
TypeError: Cannot convert object to primitive value
翻译:不能将对象转换为原始值 查阅资料发现引用类型向原始类型转换遵循ToPrimitive规则
⭐️ToPrimitive规则
是引用类型向原始类型转变的规则,它遵循先valueOf后toString的模式期望得到一个原始类型。如果还是没法得到一个原始类型,就会抛出 TypeError。
三、总结
1.明确转换类型:
如alert,console.log明确引用类型是要转换为字符串类型,那么采用的策略是先toString后valueOf。
2.不明确转换类型:
如隐式类型转换,那么采用ToPrimitive规则,遵循先valueOf后toString的模式期望得到一个原始类型。
MDN中valueOf()方法的返回值:
toString方法返回值
3.返回值:
在复写这两个函数时,函数返回值起着关键作用,可以决定调用几个方法和最后函数的返回值。好好利用这一特点与隐式自动调用的模式,助力成为装逼达人!
4.注意点:
alert会将两个方法最后得到的原始类型值进行返回
但是console.log不会,还是返回函数体。
其他引用类型类似,可以自己动手试试。
四、问题
对于console.log这个操作不太理解,使用alert阻塞。可以看到先提示调用方法,但是确认完alert弹窗之后,居然console.log打印语句出现在了上面。实在是不理解,希望有懂的大佬不吝赐教。
Array.prototype.toString = function () {
console.log('array-----调用toString方法')
alert('array-----调用toString方法')
return 1
}
Array.prototype.valueOf = function () {
console.log('array-----调用valueOf方法')
alert('array-----调用valueOf方法')
return 1
}
Function.prototype.toString = function () {
console.log('function-----调用toString方法')
alert('function-----调用toString方法')
return 1
}
Function.prototype.valueOf = function () {
console.log('function-----调用valueOf方法')
alert('function-----调用valueOf方法')
return 1
}
let arr = new Array()
let fn = function () {
console.log('函数内打印')
}
console.log(arr);
console.log(fn);
五、踩坑心得
事情是这样的,学习的时候看到一篇文章,对照着文章中的进行实践操作却得不到一样的结果,于是顺藤摸瓜摸出了这么多瓜。。。从柯里化到隐式调用到隐式类型转换。
第一次写博客!有写错的地方写得不好的地方请大家一定要指出来!