# js拆箱和装箱
- 装箱:把基本数据类型转化为对应的引用数据类型的操作
每当读取一个基本类型的时候,后台就会创建一个对应的基本包装类型对象,从而可以调用一些方法来操作这些数据。
var s1 = "abc";
var s2 = s1.indexOf("a")
变量s1是一个基本类型值,它不是对象,它不应该有方法。但是js内部完成了一系列处理(即装箱),使得它能够调用方法,实现的机制如下:
(1)创建String类型的一个实例;
(2)在实例上调用指定的方法;
(3)销毁这个实例;
下面来看看代码实现:
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
这样就完成装箱,我们也就能在s1上调用方法了
引用类型与原始值包装主要不同于生命周期,new创建的引用类型在离开作用域销毁,而 自动创建的原始包装对象只存在于访问他的那行代码执行期间 ,也就意味着不能在运行时给原始值添加属性和方法
let s='k11'
s.color='blue'
console.log(s.color)//undefind
let t=new String('k12')
t.color='orange'
console.log(t.color)//orange
- 拆箱:将引用类型对象转换为对应的值类型对象
它是通过引用类型的valueOf()或者toString()方法来实现的。如果是自定义的对象,你也可以自定义它的valueOf()/tostring()方法,实现对这个对象的拆箱。 如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。
var objNum = new Number(123);
var objStr =new String("123");
console.log( typeof objNum.valueOf() ); //number
console.log( typeof objStr.valueOf() ); //string
console.log( typeof objNum.toString() ); // string
console.log( typeof objStr.toString() ); // string
# 创建基本类型的方法
# 加new 和不加new创建基本类型
- 字面量类型声明和new类型声明生成的结果表面一致,但是如下,用new生成的String还可以添加其他属性,而字面量的声明的即使声明了也会被忽略
let a1 ='a1'
let a2 = new String('a2')
let a3 = String('a3')
a1.name='zs'
a2.name='ls'
a3.name='ww'
console.log(a1)
console.log(a2)
console.log(a3)
console.log(a1.name)
console.log(a2.name)
console.log(a3.name)
console.log(typeof a1)
console.log(typeof a2)
console.log(typeof a3)
console.log(a2+'333')
console.log(a2.name)
// a1
// String {'a2', name: 'ls'}
// a3
// undefined
// ls
// undefined
// string
// object
// string
//a2333
//ls
# toString()
# Boolean型
var obj = new Boolean(true);
console.log(obj.toString());//"true"
console.log(typeof obj.toString());//string
//如果是包装类型的基本类型,则返回原基本类型值
var a = true;
console.log(a.toString());//"true"
console.log(typeof a.toString());//string
如果是基本包装类型对应的基本类型,会返回原值。但这并不代表基本类型拥有toString()方法,只是如上的装箱操作。
# String型
String基本包装类型和基本类型调用toString()方法都返回对应的字符串
# Number型
var obj = new Number("123");
console.log(obj.toString());//123
console.log(typeof obj.toString());//string
//如果是包装类型的基本类型,则返回原基本类型值
var a = 123;
console.log(a.toString());//123
console.log(typeof a.toString());//string
Number基本包装类型和基本类型调用toString()方法都返回对应的字符串。
如果直接用整数调用时,要加上括号,否则会报错。因为整数后面的点会识别为小数点。浮点型不会报错。
console.log(123.toString());//Uncaught SyntaxError
console.log((123).toString());//"123"
console.log(12.3.toString());//"12.3"
数字类型的toString()方法可以接收表示转换基数(可选,2-36中的任何数字),如果不指定此参数,转换规则将是基于十进制
var n = 33;
console.log(n.toString());//'33'
console.log(n.toString(2));//'100001'
console.log(n.toString(3));//'41'
console.log(n.toString(37));
//Uncaught RangeError: toString() radix argument must be between 2 and 36
# 数组Array类型 返回数组内容组成的字符串
var a = [1,2,3,4];
console.log(a.toString());//"1,2,3,4"
# 函数Function类型(返回函数代码字符串)
# 正则RegExp类型(返回原正则表达式的字符串表示)
# Date类型(返回表示当前时间的字符串)
# 对象Object类型及自定义对象类型([object Object])
var obj = {a:1};
console.log(obj.toString());//"[object Object]"
console.log(typeof obj.toString());//string
function Foo(){};
var foo = new Foo();
console.log(foo.toString());//"[object Object]"
console.log(typeof foo.toString());//string
TIP
- undefined和null没有此方法(基本类型肯定没有方法,String、Number和Boolean是因为有对应的基本包装类型,才可以调用方法)
- Object类型返回字符串“[object Object]”
- 函数返回字符串,具体看浏览器自身解析
# valueOf()
# Boolean型
var obj = new Boolean(true);
console.log(obj.valueOf());//true
console.log(typeof obj.valueOf());//boolean
//如果是包装类型的基本类型,则返回原基本类型值
var a = true;
console.log(a.valueOf());//true
console.log(typeof a.valueOf());//boolean
- 如果用new创建一个布尔值,要注意他是个对象,那么判断的时候就是true
let falseObject = new Boolean(false);
console.log(falseObject)//Boolean {false}
let result = falseObject && true;
console.log(result); // true
let falseValue = false;
result = falseValue && true;
console.log(result); // false
# String型 Number型
返回原值
- 数组Array类型(返回原数组)
- 函数Function类型(返回原函数)
# Date类型(返回表示当前时间的数值)
# getTime
var obj = new Date();
console.log(obj);//Wed May 10 2017 12:19:05 GMT+0800 (中国标准时间)
console.log(obj.valueOf());//1494389910179
console.log(obj === obj.valueOf());//false
console.log(obj.getTime() === obj.valueOf());//true
小结
- undefined和null没有此方法
- 基本包装类型和对应的基本类型,调用valueOf()返回对应的基本类型值;
- 对象类型(除Date类型)返回原对象;
- Date类型返回表示日期的毫秒数
更便捷的获取当前时间的毫秒数 +new Date(=new Date.valueOf())
# valueOf 和 toString 优先级
二者并存的情况下,在数值运算中,优先调用了valueOf,字符串运算中,优先调用了toString。
class A {
valueOf() {
return 2
}
toString() {
return '哈哈哈'
}
}
let a = new A()
console.log(String(a)) // '哈哈哈' => (toString)
console.log(Number(a)) // 2 => (valueOf)
console.log(a + '22') // '222' => (valueOf)
console.log(a == 2) // true => (valueOf)
console.log(a === 2) // false => (严格等于不会触发隐式转换)
class A {
valueOf() {
return 2
}
}
let a = new A()
console.log(String(a)) // [object Object]==>调用了对象原型的方法toString;可以把Object.protoptype.toString=null测试
console.log(Number(a)) // 2 => (valueOf)
console.log(a + '22') // '222' => (valueOf)
console.log(a == 2) // true => (valueOf)
console.log(a === 2) // false => (严格等于不会触发隐式转换)
class A {
toString() {
return '哈哈哈'
}
}
let a = new A()
console.log(String(a)) // '哈哈哈' => (toString)
console.log(Number(a)) // NaN => (toString)
console.log(a + '22') // '哈哈哈22' => (toString)
console.log(a == 2) // false => (toString)
# [Symbol.toPrimitive]
Symbol.toPrimitive 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。
- 作用:同valueOf()和toString()一样,但是优先级要高于这两者;
- 该函数被调用时,会被传递一个字符串参数hint,表示当前运算的模式,一共有三种模式:
- string:字符串类型
- number:数字类型
- default:默认:比较特殊的是(+)拼接符,这个属于default的模式。
class A {
constructor(count) {
this.count = count
}
valueOf() {
return 2
}
toString() {
return '哈哈哈'
}
// 我在这里
[Symbol.toPrimitive](hint) {
if (hint == "number") {
return 10;
}
if (hint == "string") {
return "Hello Libai";
}
return true;
}
}
const a = new A(10)
console.log(`${a}`) // 'Hello Libai' => (hint == "string")
console.log(String(a)) // 'Hello Libai' => (hint == "string")
console.log(+a) // 10 => (hint == "number")
console.log(a * 20) // 200 => (hint == "number")
console.log(a / 20) // 0.5 => (hint == "number")
console.log(Number(a)) // 10 => (hint == "number")
console.log(a + '22') // 'true22' => (hint == "default")
console.log(a == 10) // false => (hint == "default")