类型转换之引用类型转换
js中的任何类型在做隐式转换时只存在两种:值类型转值类型,引用类型转换值类型。下面针对引用类型转换为值类型。
当一个引用类型转换为值类型的时候首先会调用valueOf方法,如果此时已经转换为值类型则结束,否则继续调用toString()方法进行转换。下面看例子
_toString=Boolean.prototype.toString;
_valueOf=Boolean.prototype.valueOf;
Boolean.prototype.valueOf=function(){
alert('do valueOf');
return {};
};
Boolean.prototype.toString=function(){
alert('do toString');
return _toString.call(this);
}
}());
var obj=new Boolean(true);
var v=false;
alert(obj+v);//truefalse
在上面的例子中,我们通过改写Boolean中的valueOf方法来使其返回一个引用类型对象,这样就迫使其必须再调用一次toString以使其返回值类型,默认的Boolean对象调用一次valueOf就已经转换为值类型(返回true而不是'true',这样参与最后的运算时输出1),所以根本不会再调用toString;最后返回'true'字符串,当’true'+false时false转换为'false'字符串
因此我们发现依次输出
do valueOf
do toString
truefalse
接下来我们再次场次修改Boolean的valueOf使其不返回对象,而是字符串'helllow javascript'
alert('do valueOf');
return {};
};
,这样意味着执行valueOf后已经返回了值类型,就不需要再次调用toString方法了,因此结果输出
do Valueof
hellow javascript
不过这样还不满足,因为我们只是一味的改 valueOf,我们尝试改下toString试试,我们让其也返回一个对象,那一味着经过toString后还是没有转换为值类型
那已经违背了我们最终必须转换为值类型的定理,因此这样的改动会报错
alert('do toString');
return {};
}
最后执行比较的时候提示”无法将obj转换为原始类型“
讲到这里最后再来一个例子
alert(arr == false);//true
上面为什么为true,我们来分析下
1、发现arr为引用类型的对象,因此调用内部的valueOf,返回还是引用类型本身。
2、根据上面valueOf返回的不是值类型,因此再次执行toString,我们知道数组执行toString会展开其内部元素,然后拼接为字符串,
因此空元素的arr.toString()后返回 空的字符串''。
3、最后我们知道空的字符串会转换为false,因此arr==false会输出true了。
空说理论无凭,我们还是以实际代码来验证
_valueOf = Array.prototype.valueOf;
_toString = Array.prototype.toString;
Array.prototype.valueOf= function(){
alert('do valueOf');
var arrValueOf = _valueOf.call(this);//执行默认的valueOf
alert(typeof arrValueOf);//输出object
return arrValueOf;//记得返回该值不至于改变默认的结果,否则相当于重写valueOf后使返回了undefined吗,这样就是告诉引擎已经是值类型了,就不会再调用toString,你可以试试
};
Array.prototype.toString = function(){
alert('do toString');
var arrToString = _toString.call(this);//执行默认的toString;
alert(arrToString);//输出空字符串'';
return arrToString;//记得返回该值不至于改变默认的结果,否则相当于重写toString后使返回了undefined;
}
}());
var arr = [];
alert(arr == false);//true
一个很有趣的问题?
[] == ![]//true