JS原始值创建背后发生的故事

647 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

引出问题🍵

Js初学者又或者是使用者都会产生这么一个疑惑: “我们声明的字符串变量为什么可以以类似对象的形式来调用方法,比如str.toString() ,当然不只是字符串类型,还有布尔数值类型,他们都属于原始值类型,本文将带你了解这三种原始值的创建,背后发生了什么,为什么可以以对象形式来调用方法,又或者是属性。

背后的类型😶‍🌫️

字符串布尔数值三者背后分别对应着三个原始值包装类型分别为**String()Boolean()Number()** ,其本质为引用类型,而正是这三种引用类型在后面帮助我们的三种原始值,我们以字符串举例,来看看当我们创建一个原始值,后台都发生了什么事情。

let str_1 = "猪痞恶霸"; 
let str_2 = str_1.substring(1); // 痞恶霸

如上我们声明了一个str_1并为其赋值,其类型为字符串类型,然后再声明一个str_2变量并调用str_1substring方法为其赋值,那么在其背后发生了什么

let str_1 = new String("猪痞恶霸"); 
let str_2 = str_1.substring(1);
str_1 = null

上面是其本质,解析一下这三行都做了什么

  • 使用String()构造一个字符串实例
  • 调用字符串实例方法为其赋值
  • 完成使用后将str_1释放(未回收)

如你所见,创建一个原始值是通过特定的引用类型构造一个实例,所以其能调用方法或者访问其属性(譬如str_1.length),那么我们可以为原始类型添加方法或者属性吗?

let str_1 = "猪痞恶霸"; 
str_1.name = "hogskin"
console.log(str_1.name) // undefined

到这里有人就疑问了,为啥捏。其实上面是隐式创建原始值,而当我们显式创建原始值的时候结果还是不同的。

let str_2 = new String("猪痞恶霸")
str_2.name = "hogskin"
console.log(str_2.name) // hogskin

使用new String()是显式创建方法,我们可以为其添加属性或者方法,短短的代码,大大的疑惑,我来解释一下为什么上面两个代码块产生不同的效果。

其实上面会出现这种情况完全由显示创建和隐式创建给实例带来不同的生命周期造成的

  • 显式创建:通过new引用类型构造实例,它的会存在与当前作用域之内,离开即销毁。
  • 隐式创建:通过直接创建引用类型,它存在于涉及到它的代码执行调用阶段。

显而易见,隐式创建的生命周期导致了无法为其添加属性或者方法。

隐式还是显式创建❔

又有掘友可能会问:我们推荐使用显式创建还是隐式创建呢?

这个问题问得好!我们下面拿布尔类型举例来看看显示创建和隐式创建的会带来什么结果

let f_1 = new Boolean(false); 
console.log(f_1 && true); // true 
let f_2 = false; 
console.log(f_2 && true); // false

为什么会产生这种现象呢,因为f_1是显式创建,创建的实例,默认处理为true,就会导致最后意想不到的结果,所以我们更推荐也是更常用的是隐式创建,其他两种类型也会因为创建方式而收到影响,最显著的影响就是类型不同

let num = 21
let num_2 = new Number(21)
console.log(typeof num_2) // object
console.log(typeof num) // number

最后

我们已经了解了三种原始类型的创建在背后会发生什么,也掌握了其不同创建方式会带来的影响,其实我们身为前端工程师更应该了解Js背后的事情,能让我更好地去理解,应用。