资讯专栏INFORMATION COLUMN

[ JS 进阶 ] 基本类型 引用类型 简单赋值 对象引用

余学文 / 1251人阅读

摘要:也就是说基本类型在赋值操作后,两个变量是相互不受影响的。前面讲引用类型的时候提到,保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。

ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型。也有其他的叫法,比如原始类型和对象类型拥有方法的类型和不能拥有方法的类型,还可以分为可变类型和不可变类型,其实这些叫法都是依据这两种的类型特点来命名的,大家爱叫啥就叫啥吧 o(╯□╰)o 。

1.基本类型

基本的数据类型有:`undefined,boolean,number,string,null.基本类型的访问是按值访问的,就是说你可以操作保存在变量中的实际的值。基本类型有以下几个特点:

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;

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

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

2.引用类型

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

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;

3.简单赋值

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

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中的值的一个副本,此后,这两个变量可以参加任何操作而相互不受影响。

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

4.对象引用

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

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

它们的关系如下图:

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85697.html

相关文章

  • 进阶4-1期】详细解析赋值、浅拷贝和深拷贝的区别

    摘要:展开语法木易杨通过代码可以看出实际效果和是一样的。木易杨可以看出,改变之后的值并没有发生变化,但改变之后,相应的的值也发生变化。深拷贝使用场景木易杨完全改变变量之后对没有任何影响,这就是深拷贝的魔力。木易杨情况下,转换结果不正确。 一、赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分 基本数据类型:赋值,赋值之后两个变量互不影响 引用数据类型:赋址,两个...

    silvertheo 评论0 收藏0
  • 进阶1-5期】JavaScript深入之4类常见内存泄漏及如何避免

    摘要:本期推荐文章类内存泄漏及如何避免,由于微信不能访问外链,点击阅读原文就可以啦。四种常见的内存泄漏划重点这是个考点意外的全局变量未定义的变量会在全局对象创建一个新变量,如下。因为老版本的是无法检测节点与代码之间的循环引用,会导致内存泄漏。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题...

    red_bricks 评论0 收藏0
  • 进阶1-4期】JavaScript深入之带你走进内存机制

    摘要:引擎对堆内存中的对象进行分代管理新生代存活周期较短的对象,如临时变量字符串等。内存泄漏对于持续运行的服务进程,必须及时释放不再用到的内存。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第4天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了解本进阶计划...

    不知名网友 评论0 收藏0
  • 夯实JS系列--变量、作用域和内存问题

    摘要:作用域链的用途,是保证对执行环境有权访问的变量和函数的有序访问。全局执行环境始终是作用域链的最后一个对象。延长作用域链虽然执行环境的类型只有两种。 最近在忙于写一个react+node的全栈博客demo,没有时间更新文章。但是还是觉得这样一忙起来不更新是不应该的。正好在空闲上下班地铁上都会再去细读js原生知识。所以打算整理、总结、系统性的分享给大家。 基本类型和引用类型 在ECMASc...

    sihai 评论0 收藏0
  • 进阶4-2期】Object.assign 原理及其实现

    摘要:木易杨注意原始类型被包装为对象木易杨原始类型会被包装,和会被忽略。木易杨原因在于时,其属性描述符为不可写,即。木易杨解决方法也很简单,使用我们在进阶期中介绍的就可以了,使用如下。 引言 上篇文章介绍了赋值、浅拷贝和深拷贝,其中介绍了很多赋值和浅拷贝的相关知识以及两者区别,限于篇幅只介绍了一种常用深拷贝方案。 本篇文章会先介绍浅拷贝 Object.assign 的实现原理,然后带你手动实...

    layman 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<