基本包装类型
js中有3个特殊的引用类型boolean numer string。
每当读取一个基本类型值的时候,后台会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法来操作这些数据。
let s1 = "text";
let s2 = s1.sunstring(2);
s1是一个基本类型,当第二行代码访问s1时,进入读取模式,从内存中读取这个字符串的值,在读取模式中访问字符串时,后台会完成下列处理
1.创建String类型的一个实例
2.在实例上调用指定的方法
3.销毁这个实例
可以想象成以下代码
let s1 = new String("text");
let s2 = s1.substring(2);
s1 = null;
引用类型与基本包装类型的主要区别是对象的生存周期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,只存在于一行代码的执行瞬间,然后立即销毁。
这意味着我们不能在运行的时候为基本类型值添加属性和方法。
let s1 = "text";
s1.color="red";
alert(s1.color);//undefined;
第二行创建的String对象在执行第三行的时候已经被销毁了。第三行创建了一个新的String对象,没有color。
装箱与拆箱
把基本数据类型转换为对应的引用类型的操作称为装箱,把引用类型转换为基本的数据类型称为拆箱。
上面介绍的“每当读取一个基本类型值的时候,后台会创建一个对应的基本包装类型对象”就是js的装箱。
将引用类型对象转换为对应的值类型对象,它是通过引用类型的valueOf()或者toString()方法来实现的。如果是自定义的对象,你也可以自定义它的valueOf()/tostring()方法,实现对这个对象的拆箱。
一般来说,对象到字符串的转换经过了如下步骤:
- 如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,js将这个值转换成字符串,并返还这个字符串结果。
- 如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么js将调用valueOf()方法。
- 否则,js无法从toString()或者valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。
一般来说,对象到数字的转换过程中,js做了同样类似的事情,但这里它会首先尝试使用valueOf()方法:
- 如果对象具有valueOf()方法,后者返回一个原始值,则js将这个原始值转换成数字,并返回这个数字。
- 否则,如果对象具有toString()方法,后者返回一个原始值,则js将转换并返回。(首先js转换成相应的字符串原始值,再继续将这个原始值转换成相应的数字类型,再返回数字)
- 否则,js抛出一个类型错误异常。
对象通过toString或valueOf方法转换为原始值,JS语言核心的内置类首先尝试使用valueOf(),再尝试使用toString()
==涉及的类型转换
在比较之前,==
的两个操作符都会进行强制类型转换
在转换不同的数据类型时,==
和 !=
操作符遵循系列基本的原则
- 如果有一个操作数时布尔值,则在比较相等性之前先将其转换为数值,即是调用Number()函数
- 如果一个操作数是字符串,另一个数时数值,在比较相等性之前先将字符串转换为数值;同理底层是Number()函数
- 如果一个操作数是对象,另一个操作数不是,则调用对象的
valueOf()方法,用得到的基本类型按照前面的规则进行比较
以上是类型转换时遵循的原则,在转换成基本数据类型以后,会出现两边都是同个类型和不同类型的情况,在进行比较时又遵循以下的原则
- null 和 undefied 是相等的,这是js的规定,但是其实在底层,undedined的值是派生自null的,所以逻辑等时要返回true
- 如果有一个操作数时NaN,则返回false(NaN不与任何操作符逻辑等或全等,包括NaN)
- 如果两个操作符都是对象,则比较它们是不是同一个对象,则返回true,否则返回false
例子
console.log(undefined==false)
console.log(null==false)
console.log(null==0)
console.log(undefined==0)
//以上都输出false
undefined == false
//根据转换规则1,调用Number()方法将其转换为数值类型
//根据上面结果,则转换为 NaN == 0
//根据比较规则2,NaN不与任何操作符逻辑等,则返回false
null == false
Number(null) == Number(false) => 0 == 0 => true //这是不行的
//可在控制台输出的是false啊?这只能说是js的特殊情况了,
//就像null == undefined一样,同样存在下列的特殊情况
null == 0 //false
null == false //false
true == 2 //false 因为Number(true)返回的是1
console.log(null==undefined)//true
console.log(null===undefined)//false
console.log(2==true)//false
//规则1 Number(true)=>1
//2==1 =>false
valueOf() toString()
var bbb = {
i: 10,
toString: function() {
console.log('toString');
return this.i;
},
valueOf: function() {
console.log('valueOf');
return this.i+10;
}
}
alert(bbb);// 10 toString
alert(+bbb); // 20 valueOf
alert(''+bbb); // 20 valueOf
alert(bbb>15);//true
alert(String(bbb)); // 10 toString
alert(Number(bbb)); // 20 valueOf
alert(bbb == '20'); // true valueOf
使用运算符的alert(+bbb);alert(’’+bbb);alert(bbb>15);都是调用的valueOf
如果只重写了toString,对象转换时会无视valueOf的存在来进行转换。
如果只重写了valueOf,对象转换时原本使用toString的会使用Object.prototype上的toString。
var aa = {
i: 10,
toString: function() {
console.log('toString');
return this.i;
}
}
alert(aa);// 10 toString
alert(+aa); // 10 toString
alert(''+aa); // 10 toString
alert(String(aa)); // 10 toString
alert(Number(aa)); // 10 toString
alert(aa == '10'); // true toString
//再看valueOf。
var bb = {
i: 10,
valueOf: function() {
console.log('valueOf');
return this.i;
}
}
alert(bb);// [object Object]
alert(+bb); // 10 valueOf
alert(''+bb); // 10 valueOf
alert(String(bb)); // [object Object]
alert(Number(bb)); // 10 valueOf
alert(bb == '10'); // true valueOf
//发现有点不同吧?!它没有像上面toString那样统一规整。
//对于那个[object Object],我估计是从Object那里继承过来的,我们再去掉它看看。
Object.prototype.toString = null;
var cc = {
i: 10,
valueOf: function() {
console.log('valueOf');
return this.i;
}
}
alert(cc);// 10 valueOf
alert(+cc); // 10 valueOf
alert(''+cc); // 10 valueOf
alert(String(cc)); // 10 valueOf
alert(Number(cc)); // 10 valueOf
alert(cc == '10'); // true valueOf
参考文章:
https://www.cnblogs.com/imwtr/p/4392041.html
《js高级程序设计》