你所不了解的js类型系统

js的类型分为两大类,基本类型和引用类型,对应内存模型中的栈和堆,这也是OOP目前主流的分类方法(Java和C#),可能叫法上面有不同,js最常用的三种基本类型

let a = "China No.1";
let b = 99999999;
let c = true;

特点是值复制,使用const修饰会锁值,不能用成员操作符增加字段,具体可以参考我写的小白都能看懂的javascript内存模型

console.warn("a.toString", a.toString());
console.warn("b.toString", b.toString());
console.warn("c.toString", c.toString());

乍一看好像会报错,实际是正常打印出结果,难道是因为使用了let产生了什么副作用,再试一下直接用字面值

console.warn("toString", "China No.1".toString());
console.warn("toString", (99999999).toString());
console.warn("toString", true.toString());

这回总该报错了吧,基本类型压根没有toString这个方法呀,然而顺利打印出结果,这回我想到是不是有类似的包装机制,查一下构造函数

console.warn("toString", "China No.1".constructor);
console.warn("toString", (99999999).constructor);
console.warn("toString", true.constructor);

果然是包装成对象,所以也就能调用原型中的方法了

demo.html:25 toString ƒ String() { [native code] }
demo.html:26 toString ƒ Number() { [native code] }
demo.html:27 toString ƒ Boolean() { [native code] }

如果展开constructor.prototype可以看到详细的信息

demo.html:31 toString String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, ...}
demo.html:32 toString Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, ...}
demo.html:33 toString Boolean {false, constructor: ƒ, toString: ƒ, valueOf: ƒ}

但是又有疑问了,包装会不会改变类型,也就是说基本类型会不会因为调用toString()之后就变成引用类型了,还是说只是临时包装,我猜测应该是临时的

let a = "China No.1";
let b = 99999999;
let c = true;

console.warn("toString", a.toString());
console.warn("toString",  b.toString());
console.warn("toString", c.toString());

console.warn("toString", a instanceof Object);
console.warn("toString",  b instanceof Object);
console.warn("toString", c instanceof Object);

终端打印出了三个大大的false,也就是说包装并未改变对象类型,只是临时借用了原型中的方法罢了,三个对象都不是Object的实例,如果我非要使用包装类呢,肯定是不能直接用字面值赋值,唯一想到的是用构造方法

let a = new String("China No.1");
let b = new Number(99999999);
let c = new Boolean(true);

console.warn("toString", a.toString());
console.warn("toString",  b.toString());
console.warn("toString", c.toString());

console.warn("toString", a instanceof Object);
console.warn("toString",  b instanceof Object);
console.warn("toString", c instanceof Object);

这回输出是三个大大的true,也就是说如果基本类型的包装类需要用构造方法,本着刨根问底的精神,常用的创建对象的方法是用字面值{},这和用new加构造方法的区别是啥

const d1 = {
	name: "韩宇",
	dance: "hiphop & locking"
};

function Dancer(name, dance){
	this.name = name;
	this.dance = dance;
}

const d2 = new Dancer("亮亮", "hiphop");

 表面上看没啥区别,都是存放两个字段,我们输出控制台

demo.html:33 d1 {name: "韩宇", dance: "hiphop $ locking"}
demo.html:34 d2 Dancer {name: "亮亮", dance: "hiphop"}

这就清楚了,d2的类型信息是Dancer而d1是默认的,也就是Object,进一步展开prototype

{constructor: ƒ}
constructor: ƒ Dancer(name, dance)
__proto__: Object

Dancer的原型是Object,或者说Dancer被绑定到了Object的原型上,Dancer向下扩展了Object的原型,而使用字面值是没有这种效果的

总结:使用字面值赋值的基本类型可以调用包装类的方法,但是要转成包装类要调用构造方法,不管是基本类型还是引用类型,被const修饰都不能重新赋值,也不能改变其类型,但是引用类型可以用"."增添字段,使用"."添加的字段和函数只对当前的对象生效,除非加在prototype里面,基本类型独占一个内存,每一次赋值都是独立的,引用类型多个对象可以共享一个内存,值对于每一个对象都是可读的,使用构造方法创建的对象独占一个prototype,而使用字面值则没有

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

free5156

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值