你所不了解的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,而使用字面值则没有

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这是一个非常有趣的问题!实际上,C++类型系统中的int类型是通过编译器解析和处理的,并不是C++语言本身定义的。因此,理论上我们可以实现一个没有int类型的C++编译器,只要它能够解析和处理其他类型就可以了。 当然,这并不是说没有int类型就能轻松通过三本考试。int类型在C++中是非常基础和常用的类型,很多算法和数据结构都需要用到它。因此,在实际编程中,使用int类型是非常必要的。 但如果你想了解如何实现一个没有int类型的C++编译器,可以从以下几个方面入手: 1. 定义自己的数据类型:你可以定义自己的数据类型来代替int类型,例如使用long long或者unsigned int等。这样虽然不能完全替代int类型,但可以满足很多基本的需求。 2. 使用模板:C++中的模板可以让你定义通用的函数和类,这样可以避免使用具体的数据类型。例如,你可以使用模板来实现通用的排序算法,而不需要使用具体的int类型。 3. 学习其他语言:如果你对C++的类型系统不满意,可以学习其他编程语言,例如Python、JavaScript等。这些语言的类型系统可能更加灵活和强大,可以让你更加自由地处理不同类型的数据。 总之,C++中的int类型虽然非常基础和常用,但并不是必须的。如果你想尝试自己实现一个没有int类型的C++编译器,可以从定义自己的数据类型、使用模板和学习其他语言等方面入手。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

free5156

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

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

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

打赏作者

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

抵扣说明:

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

余额充值