前言
在JavaScript的学习中,包装类是我们不可缺少的一类知识,可以说是干货中的干货。本文会用通俗易懂的语言,带着大家一起去领略包装类的魅力,文章中会用一些实例来便于大家理解,再附上一道阿里面试题加强记忆。如有错误,欢迎大家指正。
那么学习过JavaScript的人都知道,我们经常会遇到一些数据类型导致的输出问题,特别是我们在初学的时候,那可真是百思不得其解。
例如下面这段代码
var num =123
num.abc = 'hello'
console.log(num.abc);
输出什么大家可以自行去尝试一下。
那么带着这个问题我们开始本文的讲解,考虑到看我这篇文章的人群大部分是初学者,所以我将从最基础的知识慢慢地剖析一下包装类的概念。
JavaScript的数据类型
--js的数据类型可以分为两类:原始数据类型与引用数据类型
原始数据类型
总共可以分为五种:
numberStringBooleanundefinednull
引用数据类型
- 对象
- 数组
- 函数
- 正则表达式
- 日期
在JavaScript的语法中,引用数据类型本质可以说都是对象,那么对于对象来说,可以添加很多的属性和方法,访问的方式可以用 . (点号)或 [ ] (中括号)。而原始数据类型是绝对不能添加属性和方法的。
所以在上述代码
var num =123
num.abc = 'hello'
console.log(num.abc);
我们会发现输出结果为undefined(不是报错,只是没赋值),那么看到这里,肯定有很多人已经傻眼了,这不是跟上面的知识相违背吗?
这里便是包装类的奥妙所在了。
那么在解答这个问题之前,我还要先补充一些对象的知识:
对象创建
对于对象的创建,大家应该都不会陌生这种创建方式:
var obj = {}
这种创建方式也叫对象字面量。是我们最常用的一种创建方法。那么我还要介绍一些其他的创建方式:
1.使用内置构造函数:
let obj = new Object()
这种方式用到了一个叫做构造函数的东西,可能大家会有些陌生。那么构造函数其实与普通的函数并无区别,只不过构造函数是专门用于创建对象的,而且函数名首字母要大写。对于内置构造函数,js中绝大多数的数据类型都有属于自己的构造函数,例如常见的Number(),String()。
2.使用自定义构造函数
先定义构造函数
function Obj (name,age){
this.name=name,
this.age=age
}
再去调用,使用new
let obj1 = new Obj()
这样就能创建出一个含有构造函数中属性的实例对象,非常便于我们批量化生产对象。
构造函数中的this关键字我们先不讨论,姑且我们认为this是一个对象,这里我们要重点关注new关键字。对于函数的调用,为什么要用加一个new?
我带大家来详细的分析一下:
我们先把目光转向构造函数,我们会发现除了定义了属性,没有再有任何的操作,而且没有return语句。既然没有return语句,那obj1在函数调用中如何去获取值呢?是不是有点烧脑,那么细心的你会发现,调用时我们还用了new,那么这个new究竟做了什么?
new相当于在原函数中生成一个this对象,且运行函数中的代码语句完成赋值,最后return
用代码来看就是:
//在原函数中
let this {
name=name,
age=age
}
return this
这样的话也自然而然创建了一个对象,到这也将对上述的问题完美的解答了出来。new的功能是显而易见的。
好了,到这包装类就差不多要浮出水面了,我们终于要一探它的究竟了。
包装类
我先给出一段代码:
var num = new Number(123)
num.name = 'Bill'
console.log(num.name)
console.log(num*2)
是不是和开头那段代码很相似,只不过这里的num是一个对象,那么这里的(num.name)很多人应该都猜到是Bill了,那么这个num乘以2的值还是按照Number类型来计算的吗?是的,输出为246。这里大家可能还是会很疑惑,这个num它到底是个对象还是个Number?
结论是:JS引擎在执行这份代码时,num添加属性时被识别为对象,参与四则运算时又被识别为数字。
JS引擎会根据变量的值来确定其数据类型。如果变量存储的是原始数据类型的值,那么该变量将被视为原始数据类型。如果变量存储的是一个对象,那么该变量将被视为对象数据类型。是不是很神奇,这也是JavaScript的特色:动态类型。
那么我们回到开头那段代码
var num =123
num.abc = 'hello'
console.log(num.abc);
既然num在添加属性时可以被识别为对象,那么输出num.abc时为什么没有值而不是hello?
当我们尝试在一个原始数据类型(数字)上访问属性(num.abc)时,JavaScript 引擎会自动将该原始数据类型包装成相应的对象包装类,以便访问属性和方法,但是这些包装类在访问属性后不会保留在内存中,它们在访问完成后会被销毁。好,包装类终于出来了。
所以上述的代码就被隐式的执行成:
var num = new Number(123)
num.abc = 'hello'
delete num.abc
console.log(num.abc);
这里的new Number(123)就是一个Number类型包装类,给num添加完属性abc时创建一个包装类,再delete掉,输出语句中再创建一个新的包装类并添加属性但无没有赋值,所以这也解释了为什么打印出来时undefined。
那么到这里大家应该对包装类已经有了初步的认识。
包装类的概念
包装类是一种特殊的对象类型,它们用于将原始数据类型(如字符串、数字和布尔值)转换为对象,以便能够访问对象的属性和方法。这些包装类包括 String、Number 和 Boolean。当你尝试在原始数据类型上访问属性或方法时,JavaScript 引擎会自动创建相应的包装类实例,用于临时封装原始值。
以下是几种常见的包装类和它们的用法:
-
String 包装类:用于将原始字符串转换为对象,使你能够访问字符串的属性和方法。例如:
javascriptCopy code var str = "Hello, World"; var strObject = new String(str); // 创建一个 String 包装类 var length = strObject.length; // 使用包装类的属性 var uppercase = strObject.toUpperCase(); // 使用包装类的方法 -
Number 包装类:用于将原始数字转换为对象,允许你访问数字的属性和方法。例如:
javascriptCopy code var num = 42; var numObject = new Number(num); // 创建一个 Number 包装类 var floatValue = numObject.toFixed(2); // 使用包装类的方法 -
Boolean 包装类:用于将原始布尔值转换为对象,使你能够访问布尔值的属性和方法。例如:
javascriptCopy code var bool = true; var boolObject = new Boolean(bool); // 创建一个 Boolean 包装类 var valueOf = boolObject.valueOf(); // 使用包装类的方法
需要注意的是,包装类是临时创建的对象,它们的属性和方法调用后,并不会对原始值本身进行修改。包装类的实例在访问之后往往会被销毁(也就是delete语句),所以不会对性能造成严重的开销。
通常情况下,你不需要显式(自己写出来的代码)地创建包装类实例,因为 JavaScript 引擎会在需要时自动进行包装和拆包操作。这使得你能够使用原始数据类型的属性和方法,而无需显式创建包装类。
包装类的作用
- 提供额外的方法和属性:包装类为原始数据类型添加了一些有用的方法和属性,以便更方便地处理这些数据类型。例如,
String包装类提供了字符串长度属性、字符串查找方法等,Number包装类提供了数字的四舍五入方法、小数点精度控制等。 - 实现类型转换:包装类可以用于将原始数据类型转换为对象,从而可以利用对象的特性来操作数据。这在某些情况下是必要的,例如在使用某些对象相关的 API 时。
- 允许访问原始数据类型的方法:包装类还可以用于调用原始数据类型上的一些方法。例如,你可以使用
String包装类来访问原始字符串上的方法,尽管它并不是最常见的做法。
阿里面试题
var str = 'abc'
str += 1
var test = typeof(str) //
if(test.length==6){// new String(test).length
test.sign ='typeof的返回结果可能为String'
}
console.log(test.sign);
- 定义一个字符串,
str += 1得到新的字符串'abc1'。(字符串类型与任意类型相加结果都是字符串类型) - 然后定义test变量,并调用
typeof内置函数(返回一个表示数据类型的字符串),所以test被赋值为string。 - 满足
if的判断条件,进入if语句,给test添加一个属性sign并赋值。
这里实际上就是隐式的创建了一个Srting包装类,执行完语句后,delete掉,写成代码就是:
new String(test).sign ='typeof的返回结果可能为String'
delete ...
最后打印test.sign,又要创建一个包装类,但是未赋值,所以最终答案为undefined。
总结
本篇比较干,我力求以小白的视角为大家深入剖析,真诚期待每一位读者都能对包装类有更深刻的认知。
有任何想法和建议欢迎大家在评论区留言哦~
点个免费的赞鼓励支持一下吧!
个人Gitee仓库:Code Space: 记录学习code中的点点滴滴 (gitee.com)