JS基础-揭开包装类的神秘面纱,原来js也就这么回事

JavaScript 的数据类型

JavaScript 是一种动态、弱类型的语言。虽然 JavaScript 的类型系统不像静态类型语言那样严格,但它仍然有自己的类型系统,并通过不同的方式管理和操作这些类型。

JavaScript 的数据类型可以分为原始类型(Primitive Types)对象类型(Object Types)

原始类型(基础类型)

  1. String :字符串,例如 "hello"
  2. Number :数字,包括整数和浮点数,例如 423.14
  3. Boolean :布尔值,只有两个值:truefalse
  4. BigInt :用于表示大整数,例如 123n
  5. Symbol :一种唯一且不可变的值,用作对象属性的标识符,例如 Symbol("description")
  6. Undefined:表示变量未定义或未赋值
  7. Null:表示空或不存在的值

对象类型

  • Object:对象是引用类型,用于存储键值对和复杂数据结构。
  • Function:JavaScript 中的函数也是对象,是一种特殊的对象类型。
  • Array:数组是对象的一种,用于存储有序的值列表。
  • 其他对象类型 :如 DateRegExp 等。

原始类型与对象类型的主要区别

  1. 存储方式

    • 原始类型直接存储在栈内存中,访问速度快。
    • 对象类型存储在堆内存中,引用存储在栈内存中。
  2. 可变性

    • 原始类型是不可变的,一旦创建,值就不能改变。
    • 对象类型是可变的,属性和内容可以动态改变。
  3. 传递方式

    • 原始类型按值传递,变量赋值时会创建副本。
    • 对象类型按引用传递,变量赋值时会复制引用,多个变量可以引用同一个对象。

万物皆对象?

大家都知道,JavaScript同时也是一门面向对象的语言,我们尊崇"万物皆对象",咦?那既然如此,基础类型和他们所对应的对象类型又如何区分呢?为了不打起来,JavaScript做出了妥协,为部分基础类型系统中的"值类型"设定对应的包装类 ;然后通过包装类,将"值类型数据"作为对象来处理。

什么鬼东西?

先别急着刀人 我们来看个栗子

js 复制代码
let str ='I love you'
console.log(str.length);

let num = 23
console.log(num.length)

虽然我们经常用到str.length,但有没有想过,为什么str就有,而num就没有呢? 其实呢 是这样的

对于str

  • 原始类型str 是一个原始类型的字符串。

  • 临时包装对象 :当你访问 str.length 时,JavaScript 引擎创建一个临时的 String 对象来包装这个原始字符串。

  • 属性查找 :JavaScript 在这个临时 String 对象的原型链上查找 length 属性。由于 String.prototype 上定义了 length 属性,查找成功。

  • 返回值length 属性的值是字符串的长度,因此返回 10。

  • 丢弃临时对象 :访问完成后,临时的 String 对象被丢弃。

而对于num

  • 原始类型num 是一个原始类型的数字。

  • 临时包装对象 :当你访问 num.length 时,JavaScript 引擎创建一个临时的 Number 对象来包装这个原始数字。

  • 属性查找 :JavaScript 在这个临时 Number 对象的原型链上查找 length 属性。由于 Number.prototype 上没有 length 属性,查找失败。

  • 返回值 :由于临时的 Number 对象没有 length 属性,因此返回 undefined

  • 丢弃临时对象 :访问完成后,临时的 Number 对象被丢弃。

相信大家都理解了吧,那么如果你看了你知道new会发生什么吗这篇文章,相信你可以理解下面的例子

js 复制代码
let str = new String('Hello');
console.log(typeof str);        // 输出 "object"
console.log(str.valueOf());     // 输出 "Hello"

let num = new Number(123.456);
console.log(typeof num);        // 输出 "object"
console.log(num.valueOf());     // 输出 123.456

那么 对于上面的new和我们这段代码又有什么区别呢?

js 复制代码
let num =123
let str='Hello'

当然有

js 复制代码
console.log(str1 == str2); // 输出: true (因为==比较值) 
console.log(str1 === str2); // 输出: false (因为===比较类型和值)

我们可以看见 两者的值都是一样的,但是由于类型不同而第二条输出false,所以说,由new创建的num和str都是和我们直接赋值一样都有一个值的,但是,前者是一个包装类。但是呢,包装类创建的对象占用更多内存,并且性能上相对较慢,因为每次创建对象时都需要分配内存和垃圾回收。基本类型更轻量,性能更高,因为它们直接在栈上操作,而不是在堆上。

最后 我们以一道面试题来结束

js 复制代码
var str = 'abc'
str += 1
console.log(str);
var test = typeof (str)
if (test.length === 6) {
    test.sign = 'typeOf的返回结果可能是String' 
  
}
console.log(test.aign)//undefined 
  • 加号在这里是链接字符串 所以str-->'abc+1'
  • 所以test-->'String'
  • 所以if判断为真执行test.sign='typeOf的返回结果可能是String'
  • 这里引擎会干这么几件事
    • 创建一个String对象并且增加sign属性,new String(test).sign='typeOf的返回结果可能是String'
    • 访问完毕,然后发现test为原始类型,丢弃该String对象。
  • 所以最后的输出引擎找不到该属性而输出undefined 了解包装类有助于我们理解代码并运用一些隐式地转换简化我们的代码,更为透彻理解引擎的执行。
相关推荐
Мартин.7 分钟前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。2 小时前
案例-表白墙简单实现
前端·javascript·css
数云界2 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd2 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常2 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer2 小时前
Vite:为什么选 Vite
前端
小御姐@stella2 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing2 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing2 小时前
WebGL在低配置电脑的应用
javascript
eHackyd2 小时前
前端知识汇总(持续更新)
前端