你不知道的JavaScript--Item4 基本类型和基本包装类型(引用类型)

本文详细解析JavaScript中的基本类型与引用类型的区别,包括生命周期、特点及操作方法,并对比基本类型与引用类型的存储方式与比较机制。通过具体代码示例,阐述基本类型与引用类型在赋值、方法调用、属性添加等方面的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、基本类型和引用类型

基本的数据类型有5个:undefined,boolean,number,string,null

typeof null;   //"object"
typeof undefined;  //"undefined"
typeof 1;  //"number"
typeof false  //"boolean"
typeof "1"  //"string"

(令人困惑的是,对null类型进行typeof操作得到的结果为“object”,然而,ECMAScript标准描述其为一个独特的类型。)

为了便于操作基本类型值,ECMAScript还提供了三个特殊的引用类型:Boolean、Number和String,标准库提供了构造函数来封装布尔值、数字和字符串作为对象。这些类型与其他引用类型相似,同时也具有与各自的基本包装类型相应的特殊行为。实际上,每当读取一个基本类型值时,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。

var s1 = "some text";
var s2 = s1.substring(2);
var s3 = new String("some text");

但是不同于原始的字符串,String对象是一个真正的对象。

typeof s1;  //"string"
typeof s3;  //"object"

这个例子中的变量s1包含一个字符串,字符串当然是基本类型值。而下一行调用了s1的substring()方法,并将返回的结果保存在s2中。我们知道,基本类型值不是对象,因此从逻辑上讲,它们不应该有方法(但是它们确实有方法)。其实,为了让我们实现这种直观的操作,后台已经自动完成了一系列的处理。当第二行代码访问s1时,访问过程处于一种读取模式,也就是从内存中读取这个字符串的值。而在读取模式中访问字符串时,后台都会自动完成下列处理:

(1)创建String类型的一个实例。

(2)在实例上调用指定方法。

(3)销毁这个实例。

可以使用以下代码表示:

var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

经过此番处理,基本的字符串值就变得跟对象一样了。而且,上面三个步骤也适用于Boolean和Number类型对应的布尔值和数字值。

2、生命周期

引用类型与基本包装类型的主要区别就是对象的生命周期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,只存在于这一行代码的执行期(瞬间),然后立即销毁。这就意味着我们不能在运行时为属性添加属性和方法。

var s1 = "some text";
s1.color = "red";
alert(s1.color); //undefined

当然,可以显示调用Boolean、Number和String来创建基本包装类型的对象,不过,不帮不建议这么做。对基本包装类型的实例调用typeof会返回”object”,而且所有基本包装类型的对象都会被转化为布尔值true。。

var obj = new Object("some text");
alert(obj instanceof String) //true

值得注意的是,使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。

var value = "25";
var number = Number(value);//转型函数
alert(typeof number) //number

var obj = new Number(var); //构造函数
alert(typeof obj) //object

3.基本类型特点

1.基本类型的值是不可变得:

任何方法都无法改变一个基本类型的值,比如一个字符串:

var name = 'jozo';
name.toUpperCase(); // 输出 'JOZO'
console.log(name); // 输出  'jozo'

会发现原始的name并未发生改变,而是调用了toUpperCase()方法后返回的是一个新的字符串。
再来看个:

var person = 'jozo';
person.age = 22;
person.method = function(){//...};

console.log(person.age); // undefined
console.log(person.method); // undefined

通过上面代码可知,我们不能给基本类型添加属性和方法,再次说明基本类型时不可变得;

2.基本类型的比较是值的比较:

只有在它们的值相等的时候它们才相等。
但你可能会这样:

var a = 1;
var b = true;
console.log(a == b);//true

它们不是相等吗?其实这是类型转换和 == 运算符的知识了,也就是说在用==比较两个不同类型的变量时会进行一些类型转换。像上面的比较先会把true转换为数字1再和数字1进行比较,结果就是true了。 这是当比较的两个值的类型不同的时候==运算符会进行类型转换,但是当两个值的类型相同的时候,即使是==也相当于是===。

var a = 'jozo';
var b = 'jozo';
console.log(a === b);//true

3.基本类型的变量是存放在栈区的(栈区指内存里的栈内存)

假如有以下几个基本类型的变量:

var name = 'jozo';
var city = 'guangzhou';
var age = 22;

那么它的存储结构如下图:

这里写图片描述

栈区包括了 变量的标识符和变量的值。

4.引用类型特点

引用类型会比较好玩有趣一些。

javascript中除了上面的基本类型(number,string,boolean,null,undefined)之外就是引用类型了,也可以说是就是对象了。对象是属性和方法的集合。也就是说引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。来看看引用类型的一些特性:

1.引用类型的值是可变的

我们可为为引用类型添加属性和方法,也可以删除其属性和方法,如:

var person = {};//创建个控对象 --引用类型
person.name = 'jozo';
person.age = 22;
person.sayName = function(){console.log(person.name);} 
person.sayName();// 'jozo'

delete person.name; //删除person对象的name属性
person.sayName(); // undefined

上面代码说明引用类型可以拥有属性和方法,并且是可以动态改变的。

2.引用类型的值是同时保存在栈内存和堆内存中的对象

javascript和其他语言不同,其不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用,所以引用类型的值是按引用访问的。

准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。
假如有以下几个对象:

var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};

则这三个对象的在内存中保存的情况如下图:

这里写图片描述

3.引用类型的比较是引用的比较

var person1 = '{}';
var person2 = '{}';
console.log(person1 == person2); // true

上面讲基本类型的比较的时候提到了当两个比较值的类型相同的时候,相当于是用 === ,所以输出是true了。再看看:

var person1 = {};
var person2 = {};
console.log(person1 == person2); // false

可能你已经看出破绽了,上面比较的是两个字符串,而下面比较的是两个对象,为什么长的一模一样的对象就不相等了呢?

别忘了,引用类型时按引用访问的,换句话说就是比较两个对象的堆内存中的地址是否相同,那很明显,person1和person2在堆内存中地址是不同的:

这里写图片描述

所以这两个是完全不同的对象,所以返回false;

5.简单赋值

在从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上:

var a = 10;
var b = a;

a ++ ;
console.log(a); // 11
console.log(b); // 10

此时,a中保存的值为 10 ,当使用 a 来初始化 b 时,b 中保存的值也为10,但b中的10与a中的是完全独立的,该值只是a中的值的一个副本,此后,这两个变量可以参加任何操作而相互不受影响。

这里写图片描述

也就是说基本类型在赋值操作后,两个变量是相互不受影响的。

6.对象引用

当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。前面讲引用类型的时候提到,保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响:

var a = {}; // a保存了一个空对象的实例
var b = a;  // a和b都指向了这个空对象

a.name = 'jozo';
console.log(a.name); // 'jozo'
console.log(b.name); // 'jozo'

b.age = 22;
console.log(b.age);// 22
console.log(a.age);// 22

console.log(a == b);// true

它们的关系如下图:

这里写图片描述

因此,引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操作都会相互影响。

<think>好的,我现在需要解决用户在使用Element Plus的el-select时遇到的v-model绑定无效、选中后无值的问题,特别是commodityCategoryId这个字段。首先,我得回忆一下Element Plus的相关文档常见问题。用户提到选中后无法回显,可能涉及多个方面,比如数据绑定、选项配置、Vue3的兼容性等。 根据用户提供的引用内容,有几个可能的原因。首先,引用[1]提到,如果绑定的值选项的key一致,会导致无法检测到选中的项。这可能是因为v-model绑定的值类型选项的value类型匹配,比如一个是字符串,另一个是数字。用户需要确保两者的类型一致,尤其是commodityCategoryId的类型是否正确。 然后,引用[2]指出,在el-tree-select中需要正确配置propsnode-key,类似地,在el-select中,选项的valuelabel的字段名是否正确配置。如果用户自定义了选项的字段名,比如用idname,但未在el-select中设置value-key或props,可能导致无法正确显示选中项。需要检查el-select的配置,确认是否指定了正确的value字段。 引用[3]提到在Vue3中,如果el-form的refmodel命名相同可能会导致问题,用户需要区分这两个名称。虽然用户的问题是关于el-select的,但这也可能影响到表单整体的数据绑定,需要检查是否有命名冲突的情况。 接下来,我需要整理解决步骤。首先检查v-model绑定的值是否正确,是否在data中初始化,类型是否匹配。然后,确认el-option的value绑定的commodityCategoryId是否类型一致,比如都是数字或字符串。接着,检查选项的数据结构是否正确,是否有必要的字段如valuelabel。如果使用自定义字段名,需要设置value-key或props属性。此外,Vue3的响应式系统可能要求使用ref或reactive来包装数据,确保commodityCategoryId是响应式的。最后,查看是否有表单验证或代码错误干扰了数据绑定。 可能还需要考虑异步数据的情况,比如选项数据是异步加载的,而v-model的初始值在数据加载前设置,导致无法正确显示。这时候需要确保数据加载完成后再设置初始值。 最后,生成相关问题,帮助用户进一步排查其他可能的故障点,比如Vue3的响应式问题、表单验证影响、异步数据加载等。</think>### 解决Element Plus中el-select选中后无值的问题 #### 1. **检查v-model绑定的数据类型与选项value一致性** - **问题原因**:若`v-model`绑定的`commodityCategoryId`数据类型(如数字)与`el-option`的`value`字段类型(如字符串)一致,会导致无法正确匹配选中状态。 - **解决方法**:确保`commodityCategoryId`与选项的`value`类型完全一致。例如: ```vue <el-select v-model="commodityCategoryId"> <el-option v-for="item in categoryList" :key="item.id" :label="item.name" :value="item.id" <!-- 确保此处是数字类型 --> /> </el-select> ``` 若数据来源为接口,需转换类型:`item.id = Number(item.id)`[^1]。 #### 2. **验证选项数据与v-model绑定的字段映射** - **问题原因**:若自定义了选项的字段名(如用`id`代替默认的`value`),但未正确配置`value-key`或`props`属性,会导致组件无法识别选中值。 - **解决方法**: - 在`el-select`中显式声明`value-key`字段(适用于对象类型绑定): ```vue <el-select v-model="selectedObject" value-key="id"> <el-option :value="{ id: 1, name: '食品' }" label="食品"/> </el-select> ``` - 或通过`props`配置字段映射(适用于树形选择等复杂组件)[^2]。 #### 3. **检查Vue3响应式数据声明** - **问题原因**:在Vue3中,若未使用`ref`或`reactive`声明响应式数据,`v-model`绑定可能失效。 - **解决方法**: ```javascript import { ref } from 'vue'; const commodityCategoryId = ref(''); // 初始化为空字符串或数字 ``` #### 4. **排查表单组件命名冲突** - **问题原因**:在`el-form`中,若`ref``model`的命名相同(如都叫`form`),可能导致数据绑定异常[^3]。 - **解决方法**: ```vue <el-form ref="formRef" :model="formData"> <el-select v-model="formData.commodityCategoryId">...</el-select> </el-form> ``` #### 5. **验证选项数据加载时机** - **问题原因**:若`categoryList`选项数据为异步加载,而`commodityCategoryId`在数据加载前已赋值,可能导致选项未渲染时无法回显。 - **解决方法**: ```javascript // 异步加载数据后赋值 onMounted(async () => { await loadCategoryList(); commodityCategoryId.value = preSelectedId; // 确保选项已加载完成 }); ``` #### 6. **检查表单验证干扰** - **问题原因**:若表单验证规则未通过(如必填项),可能阻止数据更新。 - **解决方法**:临时关闭验证规则,确认是否与验证逻辑相关。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值