你真的懂包装类吗......

当谈到 JavaScript 编程语言时,对象是其中一个最基本且最重要的概念之一。对象是 JavaScript 中用于存储和组织数据的基本机制之一。本文将探讨 JavaScript 中对象的基本概念、创建对象的不同方法以及如何使用对象来组织和操作数据,以及其中需要注意的地方。在讲包装类时,要先讲解对象,因为这两者密不可分。

什么是对象?

在 JavaScript 中,对象是一种复合值,它可以存储多个键值对(也称为属性)。每个属性都有一个名称(键)和一个相关联的值。这些值可以是基本类型(如字符串、数字、布尔值等),也可以是其他对象,甚至是函数。(这说的太表面了,学过c++编程语言的人,对这个概念可以理解的很清楚,刚了解'对象'的人可以把对象当做一个物种,例如人类,比作我们自己这个物种)

对象是动态的,这意味着您可以随时添加、删除或修改其属性。这使得对象成为一种非常灵活和强大的数据结构,可用于表示各种复杂的数据集合。

创建对象

JavaScript 中有几种创建对象的方法。以下是其中的一些:

1. 字面量表示法

csharp 复制代码
let person = {
    name: "John",  // 字符串
    age: 30,  // 数字
    isStudent: false  // 布尔值
    
};

2. 使用构造函数

ini 复制代码
function Person(name, age, isStudent) {  // 首字母大写或小写都行,但是大写能表现你定义的是一个构造函数,建议大写,别人也能看得懂
    this.name = name;
    this.age = age;
    this.isStudent = isStudent;
}

let person1 = new Person("John", 30, false);  // 实例化对象person
let person2 = new Person("Jerry", 18, true);  

请问这两个实例化对象一样吗?不一样,就比如你和你室友都是人,但你和他不是一样的人,因为你和他的身高,体重,性格和爱好都会不同。

构造函数本身没有return返回值,但它却能复制给实例化对象,主要依靠new这个关键字,你可以把上面一个过程这样看:

kotlin 复制代码
function Person(name, age, isStudent) {
    var this = {
    this.name = name;
    this.age = age;
    this.isStudent = isStudent;
    }
    return this
}

这样看,你也就能理解为什么没有return也可以返回值,是new完成了像这样的过程。

构造函数new的过程步骤:

  1. new会在构造函数中创建一个this对象上
  2. 执行函数中代码的逻辑 (相当于往this对象上添加属性)
  3. return this 对象

3. 使用 Object 构造函数

ini 复制代码
let person = new Object();  // Object首字母要大写
person.name = "John";
person.age = 30;
person.isStudent = false;

这是调用系统自带的构造函数

访问对象属性

要访问对象的属性,可以使用点符号或方括号表示法:

arduino 复制代码
console.log(person.name); // 输出: John
console.log(person["age"]); // 输出: 30

如果是访问不存在的属性,会出现什么?

arduino 复制代码
console.log(person.identity);  // 输出undefined

很多人会以为显示undefined很正常,恰恰相反,这个结果很不正常,它不应该报错吗,你又会觉得报错和undefined都差不多,其实差了十万八千里,你可以在全局里,写一段输出不存在的变量console.log(a);,看看结果,这段代码会报错而不是undefined,经过这两种情况的对比,你就会意识到里面有大文章。不急,我只是在这里稍微点拨一下,这个与包装类和原型链有关,后面的内容有包装类,下篇文章写原型链。

先放解释:

当您尝试访问一个对象中不存在的属性时,JavaScript 引擎会尝试在对象的原型链上查找该属性。如果在原型链上找不到该属性,JavaScript 将返回 undefined

JavaScript 对象的属性访问是通过原型链进行的。在 JavaScript 中,基本数据类型(如字符串、数字、布尔值等)不是对象,但可以像对象一样访问属性和方法。这是因为 JavaScript 会自动为基本数据类型创建对应的包装对象,这些包装对象拥有原型链,可以访问其对应的原始值。

例如,当您访问一个字符串的属性时,JavaScript 会自动将该字符串转换为一个临时的字符串对象,然后在该对象上查找属性。如果该属性不存在,则返回 undefined。这种自动创建包装对象的行为称为"自动装箱"。

因此,包装类和原型链的机制共同作用,使得在 JavaScript 中访问对象中不存在的属性时返回 undefined

修改和添加属性

ini 复制代码
person.age = 35; // 修改属性值
person["isMarried"] = true; // 添加新属性  或 person.isMarried = true

下面这里有些人可能会搞混:

ini 复制代码
var abc = 'sex'
person.abc = '男'
console.log(abc)

请问是添加了一个key为abc,value为'男'的属性,还是添加了一个key为sex,value为'男'的属性,

你可以自己试一下,印象会比较深,答案是前一种。

如果你想写出后一种,你可以这样写:

arduino 复制代码
person[abc] = '男'  

删除属性

arduino 复制代码
delete person.isStudent;

包装类 --- 隐式的过程

原始值是不能拥有属性和方法的。属性和方法是对象独有的。原始类型定义的就是原始值,原始类型有:Numbr,String,undefined,None,boll。

dart 复制代码
var num = new Number(123)
num.abc = 'hello'
console.log(num.abc);  // 123
console.log(num * 2);  // 246

num被赋值为123,说明这是原始值,但是你又使用了new关键字,使num成了个对象,添加属性,输出属性也就在理。当num*2时,执行引擎才发现你是想把num当成数字看,所以又转换成了Number类型。这是由于new带来的影响

dart 复制代码
var num = 123
num.abc = 'hello'

console.log(num)  // undefined

上面这段代码没有new,而是直接声明了一个num数字,本来num一开始就是Number类型,然后是你把num当成了对象,给num加了属性,执行引擎执行的时候突然发现这是一个Number,所以又清除了之前你把num当做对象的行为,你可以把这个过程这么看:

javascript 复制代码
new Number(123).abc = 'hello'
delete new Number(123).abc
console.log(num.abc);  // undefined

我们称上面这个过程为包装类

看下面两段代码:

ini 复制代码
var arr = [1,2,3,4,5,6]
arr.length = 2
console.log(arr);  // [1,2]
ini 复制代码
var str = 'abcde'
str.length = 2
console.log(str)  // 'abcde'

对比后,就会困惑为什么会这样?

其实就是包装类的作用,arr和str本来就是原始类型,但执行引擎会把字符串看做对象,而不会把数字看成对象,所以当执行引擎最后发现str是原始类型后,就会把前面的行为删除,这个过程如下:

javascript 复制代码
new String('abcde').length = 2
delete new String('abcde').length

阿里面试题

ini 复制代码
// 面试题
var str = 'abc'
str += 1
var test = typeof(str)
if (test.length == 6) {
  test.sign = 'typeof 的返回结果是String'
}
console.log(test.sign);

问输出是什么?

解释:

在这段代码中,首先创建了一个字符串变量 str,其初始值为 'abc'。然后,使用 += 运算符将数字 1 连接到字符串后面,相当于将 'abc'1 转换为字符串并拼接,结果为 'abc1'。接着,使用 typeof 运算符获取 str 的类型,并将结果保存在变量 test 中。

由于 typeof 返回的是一个字符串,所以 test 的值为 'string'。接下来,代码检查 test.length 是否等于 6。由于 'string' 的长度为 6,条件成立,进入 if 语句块。

if 语句块中,试图给 test 这个字符串添加一个 sign 属性,值为 'typeof 的返回结果是String'。然而,JavaScript 执行引擎发现test是个原始类型,所以会删除这个增加属性的行为。因此,test.sign 并不会成功添加属性,它仍然是 undefined

最后,通过 console.log(test.sign) 输出 undefined

因此,这段代码的输出是 undefined

最后

包装类的过程有点缺陷,要讲完原型链,才能补足这个过程,本篇篇幅过长,原型链下篇讲。

相关推荐
神夜大侠16 分钟前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱19 分钟前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号1 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72931 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲1 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
究极无敌暴龙战神X1 小时前
前端学习之ES6+
开发语言·javascript·ecmascript
王解1 小时前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里1 小时前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱1 小时前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster2 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python