(Js)探索JavaScript包装类的魅力(小白篇)

166 阅读9分钟

前言

在JavaScript的学习中,包装类是我们不可缺少的一类知识,可以说是干货中的干货。本文会用通俗易懂的语言,带着大家一起去领略包装类的魅力,文章中会用一些实例来便于大家理解,再附上一道阿里面试题加强记忆。如有错误,欢迎大家指正。

那么学习过JavaScript的人都知道,我们经常会遇到一些数据类型导致的输出问题,特别是我们在初学的时候,那可真是百思不得其解。

例如下面这段代码

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

输出什么大家可以自行去尝试一下。

那么带着这个问题我们开始本文的讲解,考虑到看我这篇文章的人群大部分是初学者,所以我将从最基础的知识慢慢地剖析一下包装类的概念。

JavaScript的数据类型

--js的数据类型可以分为两类:原始数据类型与引用数据类型

原始数据类型

总共可以分为五种:

  1. number
  2. String
  3. Boolean
  4. undefined
  5. null

引用数据类型

  1. 对象
  2. 数组
  3. 函数
  4. 正则表达式
  5. 日期

在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(123num.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 引擎会自动创建相应的包装类实例,用于临时封装原始值。

以下是几种常见的包装类和它们的用法:

  1. String 包装类:用于将原始字符串转换为对象,使你能够访问字符串的属性和方法。例如:

    javascriptCopy code
    var str = "Hello, World";
    var strObject = new String(str); // 创建一个 String 包装类
    var length = strObject.length; // 使用包装类的属性
    var uppercase = strObject.toUpperCase(); // 使用包装类的方法
    
  2. Number 包装类:用于将原始数字转换为对象,允许你访问数字的属性和方法。例如:

    javascriptCopy code
    var num = 42;
    var numObject = new Number(num); // 创建一个 Number 包装类
    var floatValue = numObject.toFixed(2); // 使用包装类的方法
    
  3. Boolean 包装类:用于将原始布尔值转换为对象,使你能够访问布尔值的属性和方法。例如:

    javascriptCopy code
    var bool = true;
    var boolObject = new Boolean(bool); // 创建一个 Boolean 包装类
    var valueOf = boolObject.valueOf(); // 使用包装类的方法
    

需要注意的是,包装类是临时创建的对象,它们的属性和方法调用后,并不会对原始值本身进行修改。包装类的实例在访问之后往往会被销毁(也就是delete语句),所以不会对性能造成严重的开销。

通常情况下,你不需要显式(自己写出来的代码)地创建包装类实例,因为 JavaScript 引擎会在需要时自动进行包装和拆包操作。这使得你能够使用原始数据类型的属性和方法,而无需显式创建包装类。

包装类的作用

  1. 提供额外的方法和属性:包装类为原始数据类型添加了一些有用的方法和属性,以便更方便地处理这些数据类型。例如,String 包装类提供了字符串长度属性、字符串查找方法等,Number 包装类提供了数字的四舍五入方法、小数点精度控制等。
  2. 实现类型转换:包装类可以用于将原始数据类型转换为对象,从而可以利用对象的特性来操作数据。这在某些情况下是必要的,例如在使用某些对象相关的 API 时。
  3. 允许访问原始数据类型的方法:包装类还可以用于调用原始数据类型上的一些方法。例如,你可以使用 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);
  1. 定义一个字符串,str += 1 得到新的字符串'abc1'。(字符串类型与任意类型相加结果都是字符串类型)
  2. 然后定义test变量,并调用typeof内置函数(返回一个表示数据类型的字符串),所以test被赋值为string
  3. 满足if的判断条件,进入if语句,给test添加一个属性sign并赋值。

这里实际上就是隐式的创建了一个Srting包装类,执行完语句后,delete掉,写成代码就是:

new String(test).sign ='typeof的返回结果可能为String'
delete ...

最后打印test.sign,又要创建一个包装类,但是未赋值,所以最终答案为undefined。

总结

本篇比较干,我力求以小白的视角为大家深入剖析,真诚期待每一位读者都能对包装类有更深刻的认知。

有任何想法和建议欢迎大家在评论区留言哦~

点个免费的赞鼓励支持一下吧!

个人Gitee仓库:Code Space: 记录学习code中的点点滴滴 (gitee.com)