小白的JavaScript包装类探秘:从基础到进阶的理解之旅
数据类型
在学习包装类之前,我们先复习一下JavaScript中的数据类型,数据类型主要分为原始数据类型和引用数据类型
1.原始数据类型
Number
:表示数值类型,可以是整数或浮点String
:表示文本类型,由一串字符组成,用引号包围Boolean
:表示逻辑值,仅有两个取值:true
和false
Undefined
:表示变量已声明但尚未赋值时的默认状态,或者访问不存在的对象属性时返回的值Null
:表示一个特殊的空值或无指向的对象引用
let a = 'hello' //数字
let b = 123 //字符串
let c = true //布尔
let d = undefined //未定义
let e = null //空值
2.引用数据类型
- 对象是键值对的集合,可以使用花括号
{}
创建,也可以通过构造函数创建 - 数组是一个有序的数据集合,允许存储任意数量和类型的元素,使用方括号
[]
创建 - 函数在JavaScript中也是一种对象,它可以被赋值给变量、作为参数传递
let obj = {} //对象
let foo = function() {} //函数
let arr = [] //数组
为什么使用包装类?
在JavaScript中,基本数据类型本身不是对象,但是在某些情况下,它们需要以对象的形式进行操作,为了实现这种操作,JavaScript提供了对应的包装类,为他们提供了一些额外的功能,允许你在基本数据类型上访问对象的属性,调用对象的方法
什么是包装类?
在JavaScript中,包装类是一组特殊的对象,用于在基本数据类型(如数字、布尔值和字符串)与对象之间进行转换和交互。JavaScript提供了三种主要的包装类:Number、String和Boolean
- Number:用于数值。例如,new Number(123) 会创建一个 Number 对象,该对象表示数值 123。
- String:用于字符串。例如,new String("hello") 会创建一个 String 对象,该对象表示字符串 "hello"。
- Boolean:用于布尔值。例如,new Boolean(true) 会创建一个 Boolean 对象,该对象表示布尔值 true
理解包装类
我们来看一个简单的demo
var num = 123
num.name = 'hhh'
console.log(num.name) //运行结果 undefined
那么问题来了,我们给一个原始数据类型的变量num
添加了属性abc
,按理来说只有对象才有属性,那么在这里为什么没有报错而显示undefined呢?
这就不得不提到了我们今天的主角包装类
实际上,这段代码在真正执行中是这样一个过程:
var num = new Number(123)
num.name = 'hello'
delete num.name
V8会通过new Number(123)
,将它进行包装创建一个Number对象,这个就叫包装,可以暂时骗过JavaScript引擎,然后可以给这个临时对象添加name属性,因为这个对象是临时的,所以并不会影响到我们真正的原始数据,众所周知JavaScript是一门动态性的语言,它在执行上下文创建阶段有一个类似于预编译的过程,在这个阶段,引擎会扫描代码并提前处理所有变量声明,在运行时由JavaScript引擎逐行解释执行,所以在预编译的过程中,我们的num
的确是具有name
属性的,但是JavaScript又有着严格的界定,属性和方法是对象独有的,原始值是不能拥有属性和方法的,所以当JavaScript引擎回过神时,会立刻删除name
属性,所以执行结果就是undefined
啦!
我们再来看一个demo
var num = 1
num.len = 2
console.log(num.len)
根据上文的介绍,我们能很轻松的get到它的运行结果undefined,那么它的执行过程是什么样的呢?
var num = new Number(1)
num.len = 2
delete num.len
new Number(1).len
这个执行过程就叫做隐式包装类
下面我们来看一个考点
var str = 'abcd'
console.log(str.length) //执行结果 4
字符串也是原始数据类型,我们可以知道的是它不能具有属性,但是V8会给它做一个隐式包装类,所以我们console.log
的其实是new String('abcd').length
,我们是可以访问到length的
那如果是这样呢?
var str = 'abcd'
str.length = 2
console.log(str) //执行结果abcd
为什么改不动呢?这又回到了我们刚刚的规则问题,字符串是不能拥有属性和方法的,所以它在创建临时对象后会删除length的值,所以我们无法修改属性值
最后看一道面试题
var str = 'abc'
str += 1
var text = typeof (str)
if (text.length == 6) {
text.sign = 'typeOf的返回结果可能为String'
}
console.log(text.sign)
我们来逐行分析一下,首先声明了一个变量str
,第二行的运行结果为abc1
,任何类型的数据在和字符串加和时都会被转换成字符串,因此在第三行类型判断后是'string'
,第四行代码会被执行为new String('string').lenth
,到了第五行V8仍然没反应过来,执行new String('string').lenth = 'typeOf的返回结果可能为String'
反应过来后再delete
掉,在打印时看到属性又new String(test).lenth
但是未赋值,所以执行结果是undefined
结语
最后,尽管JavaScript以其动态性赋予了开发者极大的灵活性,但在享受这份便利的同时,我们也应当充分认识到理解其底层原理的重要性。只有深入洞察这些内在规律,才能在实践中游刃有余,不断攀登技能高峰。希望本文能为你揭开JavaScript包装类的神秘面纱,深入了解了它在JavaScript引擎内部是如何巧妙地处理变量声明,助小伙伴们在今后的编程之旅中乘风破浪,扬帆远航。
转载自:https://juejin.cn/post/7365767783048118323