看JavaScript文档的时候注意到了这种用法var n1 = Number(123);
,冒出的第一个疑问就是和var n2 = new Number(123);
有什么区别呢?
首先用typeof
做下探测,n1是number
而n2是object
,他们的本质区别就是type不同。
有趣的是Number
内部肯定知道是怎么调用的它,假设在没有Number
的情况下,如果我要实现个类似的类应该怎么做呢?
最先想到的就是根据caller
来区分,但在实验的过程中发现两个问题:
caller
caller
也无法区分它是function
调用还是构造对象所以caller
这条路就走不通了,既然需要在运行期区分,那么该真爱this
登场了。this
指向当前构造的对象,那就可以区分是function
调用还是构造对象了。
新轮子命名为WeiWeiNumber
,思路理清楚后就剩施工了。为了更接近Number
的行为,在开工前先用测试数据探测下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
console.log(Number(123)); //123
console.log(Number(+123)); //123
console.log(Number(-123)); //-123
console.log(Number("123")); //123
console.log(Number("+123")); //123
console.log(Number("-123")); //-123
console.log(Number("abc123")); //NaN
console.log(Number(NaN)); //NaN
console.log(new Number(123)); //save as above except type
console.log(new Number(+123));
console.log(new Number(-123));
console.log(new Number("123"));
console.log(new Number("+123"));
console.log(new Number("-123"));
console.log(new Number("abc123"));
console.log(new Number(NaN));
在测试过程发现123 == new Number('123')
是返回true
的,但我们的123 == new WeiWeiNumber('123')
却返回false
,难道浏览器不给WeiWeiNumber
国民待遇?
首先分析浏览器是不可能把123 auto-box成Number
对象的,因为两个对象==
肯定是false的,所以一定是把Number
对象auto-unbox成原始type(值type)。 查了一下文档对象刚好有个valueOf()方法用来返回这个对象代表的原始值。(后来测试过程中发现valueOf()或toString()实现任一一个方法都能让浏览器返回true)
string
快速转换成number
的方法是"123" * 1 = 123
,但这是语法糖,实际上调用的是Number("123") * 1
,我们预设Number类是不存在的所以选择计算ASCII码的差值。
下面是实现WeiWeiNumber
的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function WeiWeiNumber(i){
var primitiveValue = 0;
if(typeof i === "number"){
primitiveValue = i;
}else{
//正则表达式抓取正负符号和数字的文本值
var regR = /^([\+\-]?)([0-9]+)$/.exec(i);
if(regR !== null){
//数字的文本值,相当于Java的group(2)
var nstr = regR[2];
var nstrlen = nstr.length;
//callee就是本function,避免hardcode类名
var nResult = arguments.callee(0);
for(idx in nstr){
//通过计算ASCII码的差值转换成数字
nResult += (nstr[idx].charCodeAt(0) - "0".charCodeAt(0))
* Math.pow(10, nstrlen - idx -1);
}
//判断正负值
if(regR[1] === "-"){
primitiveValue = -nResult;
}else{
primitiveValue = nResult;
}
}else{
primitiveValue = NaN;
}
}
if(this instanceof arguments.callee){
//构造对象
this.valueOf = function(){
//为了==判断返回true
return primitiveValue;
}
this.toString = function(){
//为了==判断返回true
return primitiveValue + '';
}
return this;
}else{
//invoke as function
return primitiveValue;
}
}