【专栏】包装类:赋予原始类型新的可能性(四)(含面试真题)💥

134 阅读6分钟

写在前面

欢迎来到我的专栏,《包装类:赋予原始类型新的可能性》!在这个专栏中,我们将通过数据类型、对象、构造函数、包装类四个层面进行讲解,希望你能坚持看下去!

在前面的章节中,我们详细讨论了JavaScript中的各种数据类型,特别是对象作为引用数据类型的重要性。在探讨对象创建的不同方式时,我们着重介绍了构造函数创建对象的过程,深入解析了这一创建模式。最后,让我们来探讨JavaScript中的包装类————赋予原始类型新的可能性

包装类

包装类是指JavaScript中的一组特殊对象,它们可以将原始数据类型(如数字、字符串和布尔值)转换为对象。

问题导入

我们将用几个题目来构建你对包装类的认知。

题目一:

var obj ={}
console.log(obj.a);

这里创建了一个空对象 obj,然后尝试访问对象的属性 a。输出结果什么呢?

undefined

在JavaScript中,如果你访问一个对象的不存在的属性,会返回 undefined。这意味着该属性并没有被赋值,或者该属性根本不存在于对象中。

题目二:

var num = 123;
num.abc = 'hello'
console.log(num.abc);

我创建了一个原始数据类型的变量 num 并赋值为 123。然后,我尝试在 num 上创建一个属性 abc 并赋值为 'hello',输出结果又会是什么呢?

undefined

然而,在JavaScript中,原始数据类型(如数字、字符串、布尔值等)不具备对象的特性,它们是不可变的,无法添加属性或方法。

题目三:

var num = new Number(123);
num.abc = 'hello'
console.log(num.abc);

在这段代码中,我创建了一个 Number 函数创建了一个 num,然后尝试在 num 上添加一个属性 abc 并赋值为 'hello'。输出结果又会是什么呢?

hello

image.png

啊?不是说原始数据类型无法添加属性或方法吗?

这里我们使用了new Number(123)这样的语法时,实际上创建的是一个Number实例对象,而不是原始数据类型,所以num 是一个对象,你可以给它添加属性。会打印 'hello',是因为在 num 对象上添加了属性 abc 并赋值为 'hello'

这个过程叫做包装,它会将原始数据类型(比如数字)封装成相应的包装对象,使得原始数据类型具备对象的方法和属性。


那你有没有想过这个问题:为什么访问一个原始数据类型的属性时,打印结果是undefined却不是报错呢?

这是因为,当我尝试给原始数据类型添加属性时,JavaScript 会将该数据类型临时转换成一个相应的包装对象(如数字类型的包装对象是通过 Number 构造函数创建),然后给这个临时对象添加属性。但是,这个操作不会影响到原始的数据类型。给你举个例子:

var num = 4
num.len = 3 
console.log(num.len);

我们创建了一个原始数据类型的变量 num 并赋值为 4。然后,并尝试在 num 上添加一个属性 len 并赋值为 3

在这里,JavaScript执行num.len时,引擎会将它当做一个对象属性的访问,将数字4转换为Number对象,并临时添加了len属性。但是,等到引擎缓过神来之后,它发现num是一个数字类型,会立马使用delete操作符移除这个属性。因此,num.len 在这行代码后面的操作中将是undefined

就相当于进行了以下操作:

var num = new Number(4);
num.len = 3; // 在Number对象上添加len属性
delete num.len; // 移除len属性
console.log(num.len); // 这里引擎又会上头,但是属性已经移除,打印undefined

这就是隐式包装——当你尝试在原始数据类型上调用属性或方法时,JavaScript会自动将原始数据类型转换为对应的包装对象,这个过程被称为隐式包装。


考点

请看考点

var arr = [1,2,3,4,5]
arr.length = 2
console.log(arr)

在这段代码中,创建了一个数组 arr 包含了五个元素 [1, 2, 3, 4, 5]。然后,你将数组的 length 属性设置为 2,这样就会截断数组,只保留前两个元素。

但下面这种情况呢:

var str = 'abcd'
console.log(str.length)
str.length = 2
console.log(str)

在这段代码中,你创建了一个字符串 str,其值为 'abcd'。然后,你使用console.log(str.length) 打印了字符串的长度,这里就会进行隐式包装,接着,你尝试将字符串的 length 属性设置为 2,这里又会进行一次隐式包装,我们知道这样是行不通的。

两个打印结果分别是什么呢?

4

abcd

我们分别来模拟一下两次操作隐式包装

第一次:console.log(new String('abcd').length)

第二次:new String('abcd').length = 2 ; delete num.len

我们尝试读取原始类型属性的时候,引擎会将原始类型包装成对象,可以轻而易举读取到属性,但是在修改的时候,引擎有充足的时间可以反应,当它发现它是原始数据类型的时候,就会立马删除刚才的修改。

面试题

最后我们用一道面试题来总结今日所学。

var str = 'abc'
str += 1
var test = typeof(str)
if(test.length == 6){
    test.sign = 'typeOf的返回结果可能为String'
}
console.log(test.sign);

先思考一下,假如你面试碰到了这题,该怎么应对?

在这段代码中,我首先创建了一个字符串 str,其值为 'abc'。然后,使用 += 运算符将字符串 '1' 连接到 str,使得 str 的值变为 'abc1'。接着,使用 typeof 运算符获取 str 的数据类型,结果是字符串 "string"。接下来,你将 typeof 的结果赋给变量 test。然后,你尝试读取 testlength 属性,这里会进行第一次隐式包装,得到 test.length 的值是 6,于是进入if语句,又尝试将test不存在的sign属性修改成'typeOf的返回结果可能为String',在这里就会进行第二次隐式包装,最后console.log(test.sign)进行第三次隐式包装

分别进行模拟分析:

第一次:new String('string').length == 6

第二次:new String('string').sign = 'typeOf的返回结果可能为String';delete test.sign

第三次:console.log(new String(test).sign)

在第三次进行读取的时候,引擎发现该属性已经被删除了,所以打印undefined

你做对了吗?

结语

包装类为原始类型赋予了新的可能性,使得它们能够像对象一样拥有属性和方法。然而,在实际开发中,我们应该谨慎使用包装类,避免不必要的性能开销。

至此,包装类的全部内容就讲解完毕了,如果这个专栏对你有帮助,不要吝啬你的小爱心啦,当然文章内容还需要完善,如果你有建议跟想法,欢迎评论区留言喔!


END

我的Gitee: CodeSpace (gitee.com)

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 “点赞 收藏+关注” ,感谢支持!!