5

第一百零五篇:变量的原始值和引用值 - 养肥胖虎

 1 year ago
source link: https://www.cnblogs.com/FatTiger4399/p/16861742.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

好家伙,JS基础接着学,

本篇内容为《JS高级程序设计》第四章学习笔记

1.原始值和引用值

ECMAScript变量可以包含两种不同类型的数据:原始值和引用值。原始值(primitive value)就是最简单的数据,引用值(reference value)则是由多个值构成的对象。

在把一个值赋给变量时, JavaScript引擎必须确定这个值是原始值还是引用值。

6种原始值:

1.Undefined

2.Null

3.Boolean

4.Number

5.String

6.Symbol。

引用值:

我们常见的引用值就是"对象"

保存原始值的变量是按值(by value )访问的,因为我们操作的就是存储在变量中的实际值。

(这句是真的抽象,按我的理解来,按值访问即在栈中保存的实际的数值)

引用值是保存在内存中的对象。

(这句反而好理解,我们可以把他理解为引用值保存的是一个指针,后面的例子会帮助我们更好理解)

与其他语言不同,JavaScript不允许直接访问内存位置(小东西真别致),

因此也就不能直接操作对象所在的内存空间。

在操作对象时,实际上操作的是对该对象的引用(reference)而非实际的对象本身。

为此,保存引用值的变量是按引用(by reference)访问的。

注意:在很多语言中,字符串是使用对象表示的,因此被认为是引用类型

2.动态属性

原始值和引用值的定义方式很类似,都是创建一个变量,然后给它赋一个值。

不过,在变量保存了这个值之后,可以对这个值做什么,则大有不同。

2.1.对于原始值,不能添加属性,举个例子

let panghu_1 = "panghu";
panghu_1.age =20; console.log(panghu_1.age);

看图:

2501855-20221106214345455-1516238209.png

 添加属性不会报错,但原始值不能拥有属性

2.2.对于引用值而言,可以随时添加、修改和删除其属性和方法

let panghu_2 = new String("big panghu");
panghu_2.age = 20;
console.log(panghu_2.age);

看图:

2501855-20221106214832053-1568160887.png

来看看两种值的类型判断:

2501855-20221106215154372-675471625.png

3.复制值

 原始值和引用值在通过变量复制是也有所不同.

3.1.原始值的复制

在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置.

let a = 1;
let b = a;
console.log(b);   //1

(不用上图了吧)

3.2.引用值的复制

在把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。

区别在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象。

操作完成后,两个变量实际上指向同一个对象,因此一个对象上面的变化会在另一个对象上反映出来,

(让我们提取重点.复制的值是一个指针,复制后,两个变量指向同一个对象)

让我们用代码尝试去证明:

let panghu_1 = new Object();
let panghu_2 = panghu_1;
panghu_1.age = 100;
console.log(panghu_2.age);

上图:

2501855-20221106220431614-2068206726.png

 (看,多么神奇的js)

由此可证明,将panghu_1赋值给panghu_2后,两个变量指向的其实是同一个对象

非常形象的一张图:

2501855-20221106220726892-1252614286.jpg

4.传递参数(参数的复制)

经过我们在上面的一段大发现,我们又产生了新的问题

4.1.原始值的的参数传递

function original(a){
    a= a+10;
    return a;
};
let b = 10;
let c = original(b);
console.log(b);
console.log(c);

看图:

2501855-20221106223013545-1442982527.png

 这自然是没什么悬念

4.2.初始值的参数传递

例子4.2.1.

function Reference(a) {
    a.age = 20;
};
let b = new Object();
Reference(b);
console.log(b.age);

上图,

2501855-20221106223654654-713583414.png

这怎么解释呢? 

到此为止,有的小伙伴就要说了,

创建新对象,保存在b中,将b作为参数调用方法Reference();

此时,b被赋值给了a,此时,a,b指向同一个对象,于是当我a.age=20后,

b的age属性自然就被设置为"20"了(错误的解释)

(思路非常清晰,然而这是错的)

我们加两行代码试试:

例子4.2.2.

function Reference(a) {
    a.age = 20;
    a = new Object();
    a.age = 1000;
};
let b = new Object();
Reference(b);
console.log(b.age);
上图:

2501855-20221106224246431-34623186.png

 (装一下:诶,发生甚么事了,不应该是1000吗)

于是,正确的解释来了:
我们创建了一个对象并把它保存在变量 b 中。
然后,这个对象被传给

Reference()方法,并被复制到参数a中在函数内部,a和b都指向同一个对象结果就是,
即使对象是按值传进函数的,a也会通过引用访问对象。
当函数内部给a设置了name属性时,函数外部的对象也会反映这个变化,因为a指向的对象保存在全局作用域的堆内存上。
这解释了例子4.2.1为什么发生

那例子4.2.2如何解释呢?
当a在函数内部被重写时,它变成了一个指向本地对象的指针
而那个对象在函数执行结束时就被销毁了

所以我们会知道:Js中所有函数的参数都是按值传递的


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK