第一百零五篇:变量的原始值和引用值

第一百,五篇,变量,原始,引用 · 浏览次数 : 447

小编点评

**JS高级程序设计第四章学习笔记 1.原始值和引用值** **1.原始值** * 最简单的数据类型,原始值(primitive value)就是最简单的数据,包含两种不同类型的数据:原始值(primitive value)和引用值。 **2. 引用值** * 引用值(reference value)则是由多个值构成的对象。 * 在把一个值赋给变量时, JavaScript引擎必须确定这个值是原始值还是引用值。 **3. 复制值** * 原始值和引用值在通过变量复制是也有所不同。 * 原始值的复制在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置。 * 引用值的复制在把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。 **4. 传递参数** * 原始值的参数传递:`function original(a){ a= a+10; return a;}` * 引用值的参数传递:`function Reference(a) { a.age = 20;};` **5. 初始化值的参数传递** * `function Reference(a) { a.age = 20; a = new Object(); a.age = 1000;};` **6. 总结** * JS中所有参数都是按值传递的。 * 引用值是通过多个值构成的对象。 * 原始值和引用值在通过变量复制是也有所不同。

正文

好家伙,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);

看图:

 

 

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

 

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

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

看图:

 

 

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

 

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);

上图:

 

 

 (看,多么神奇的js)

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

 

非常形象的一张图:

 

 

 

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

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

4.1.原始值的的参数传递

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

看图:

 

 这自然是没什么悬念

 

4.2.初始值的参数传递

例子4.2.1.

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

上图,

 

这怎么解释呢? 

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

创建新对象,保存在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);
上图:

 

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

 

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

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

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

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

 

 

与第一百零五篇:变量的原始值和引用值相似的内容:

第一百零五篇:变量的原始值和引用值

好家伙,JS基础接着学, 本篇内容为《JS高级程序设计》第四章学习笔记 1.原始值和引用值 ECMAScript变量可以包含两种不同类型的数据:原始值和引用值。原始值(primitive value)就是最简单的数据,引用值(reference value)则是由多个值构成的对象。 在把一个值赋给变

第一百零六篇:变量的不同声明(var,let和const的不同)

JS关于变量的声明,变量提升,暂时性死区

第一百零七篇:基本数据类型(undefined,null,boolean类型)

好家伙, 本篇内容为《JS高级程序设计》第三章学习笔记 1.数据类型 ECMAScript有6种简单数据类型(称为原始类型): Undefined, Null, Boolean, Number, String和Symbol。 Symbol (符号)是ECMAScript6新增的。还有一种复杂数据类型

第一百零八篇:最常用的基本数据类型(Number类型)

最常用的基本数据类型(Number类型)

第一百一十篇:内存泄漏和垃圾回收(JS)

好家伙,本篇内容为《JS高级程序设计》第四章的学习笔记 1.内存泄露 1.1.什么是内存泄漏? 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。 内存泄漏缺陷具有隐蔽性、积累性的特征,比其

第一百一十一篇:基本引用类型Date

好家伙,本篇为《JS高级程序设计》第五章的学习笔记 1.基本引用类型 引用值(或者对象)是某个特定引用类型的实例,在ECMAScript中,引用类型是把数据和功能组织到一起的结构,(像极了“类”) 经常被人错误的称作“类”。 虽然从技术上讲JavaScript是一门面向对象语言,但是ECMAScri

第一百一十四篇: JS数组Array(三)数组常用方法

好家伙,本篇为《JS高级程序设计》第六章“集合引用类型”学习笔记 1.数组的复制和填充 批量复制方法 copyWithin(),以及填充数组方法fill()。 这两个方法的函数签名类似,都需要指定既有数组实例上的一个范围,包含开始索引,不包含结束索引。 使用这个方法不会改变数组的大小。 1.1.fi

第一百一十五篇: JS集合引用类型Map

好家伙,本篇为《JS高级程序设计》第六章“集合引用类型”学习笔记 1.Map ECMAScript6以前,在JavaScript中实现“键/值”式存储可以使用object来方便高效地完成,也就是使用对象属性作为键,再使用属性来引用值。 但这种实现并非没有问题,为此TC39委员会专门为“键/值”存储定

第一百一十六篇: JavaScript理解对象

好家伙,本篇为《JS高级程序设计》第八章“对象、类与面向对象编程”学习笔记 1.关于对象 ECMA-262将对象定义为一组属性的无序集合。严格来说,这意味着对象就是一组没有特定顺序的值。 对象的每个属性或方法都由一个名称来标识,这个名称映射到一个值。正因为如此(以及其他还未讨论的原因),可以把 EC

第一百一十二篇: JS数组Array(一)数组基本用法

好家伙, 1.数组 Array应该就是ECMAScript中最常用的类型了。ECMAScript数组跟其他编程语言的数组有很大区别。 跟其他语言中的数组一样,ECMAScript 数组也是一组有序的数据, 但跟其他语言不同的是,数组中每个槽位可以存储任意类型的数据。 这意味着可以创建一个数组,它的第