追求JS小姊姊系列 Day24 -- 工具人、姐妹不只身份的差别(下):从记忆体看宣告变数的可变性

前情提要

被第一人视角的我打断了对话,现在要继续讲完:
D22的时候,我们知道了识别字、保留字,其中识别字缺少了宣告这件事仍可以赋值,但是它会被存於全域,易造成污染。

x1 = 2;
//window查找是否有这个属性
window.x1

所以宣告究竟能做到些什麽?


宣告 var & let & const 的差异

在下面我会将宣告的差异分成两个面向来讲解:

  1. 宣告变数的可变性
  2. 宣告变数的有效区域

在本日只会讨论 1. 宣告变数的可变性 的部分,那就开始吧!


宣告变数的可变性

不可变的const
const宣告的数值,不可重新赋值跟重新宣告。

const x = 2;
x = 1;


当你试着重新赋值时,就会显示上方的错误。

可变的let,var
varlet宣告的变数,其值可以视情况做修改;而宣告的部分:var可重复宣告,let不可重复宣告

var:

var x = 2;
var x = 1;

console.log(x);

let:

let y = 2;
let y = 1;
console.log(y);

但你有想过,可变与不可变背後 可能更好理解的原因吗?

让我们试着从记忆体的角度来看看吧?


变数是如何被存放的?

首先,你知道变数也需要存放地方吗?那是在哪呢?!

图片来源:https://tzutzu.coderbridge.io/2021/03/31/EventLoop/

以JavaScript来说分别就是

  1. Call Stack:负责存放基本型别(primitive)的值,像是1,"字串"
  2. Memory Heap:存放复合型别(non-primitive)的值,像是object等。

所以,当你每次宣告变数,并赋予基本型别值时,JS引擎其实在背後都会为变数新增记忆体空间

例如当你宣告了一个变数为2时,其实是:

let x = 2;//const or var 也是

而当你重新赋值时,实际正同时发生以下的事情:

let x = 2;
x = 1;

这时候实际上会再新建0x002的记忆体位置,并将1存入,接着x转为指向0x002的记忆体位置。

将变数值赋予另一个变数

let x = 2;

//把x值传给y
let y = x;


两个不同变数皆会指向相同记忆体位置。

修改x的值时

x将值赋予给别人後,将本身的值从2改为1

let x = 2;

//把x值传给y
let y = x;

x = 1;


从记忆体看 let & const 不变与可变

还记得上面讲到:用let宣告的变数可修改,但const则不行这件事吗?所谓的可变与不可变其实是指:记忆体位置

let允许你修改记忆体位置,但const则不行

我们先试着用const再写一次同样的内容:

const x = 2;
x = 1;


前面提过 let,const两种宣告的值是否能修改,其实是跟记忆体位置有关,因此这时自然就会报错啦~

然而,真的就这样吗?

我们同样用const宣告,这次要建立的是一个复合型别的空阵列

const x = [];

接着我们透过push帮它新增值1,2,然後印出结果

x.push(1);
x.push(2);

console.log(x);


结果却没有报错,怎麽回事呢? 一样再从记忆体来看

当你宣告了一个空阵列时,其实是长这样的

const x = [];

此时,你在Call Stack储存的其实是Heap的记忆体位置,而不再是一个值。
所以当使用push添加值却不会报错,是因为push影响的是Heap。

x.push(1);
x.push(2);

所以当我们试着重新赋值[] 时就会报错啦~

const x = [];
x = [];


因为x = []对於记忆体来说是其实会让callstack再新增一个记忆位置,并将x指向它,因此就会报错

从上面的示范,应该就能简单说明,为何同样以const宣告,基本型别与复合型别却有不同的结果吧~


:但这样还是没有解释到为何宣告能预防全域污染这件事啊...
方函式:别急,至少现在你能理解工具人与姐妹之间的差异是:~~

  1. 是否具有能力(methods,properties)
  2. 变数储存的记忆体位置也不同

-- to be continued --


那今天就到这边搂!
每天的休息,是为了後面的追求,明天见。


reference:
  1. JavaScript’s Memory Model
  2. [笔记] 谈谈 JavaScript 中 by reference 和 by value 的重要观念
  3. 深入探讨 JavaScript 中的参数传递:call by value 还是 reference?
  4. JavaScript 核心观念(29)-物件-Call by Reference 还是 Call by Sharing

<<:  D25 - 「不断线的侏罗纪」:然後他就死掉了

>>:  Day30 撒花~

JavaScript 从 100% 继续,再多程序语言也不是问题!

大家好! 自从系列开始到昨天,也已经流逝 45 天的时间了。 这期间,总是会怀疑自己写的文章够不够好...

Day29 使用 addTransceiver 单向接收串流

前面我们使用 RTCPeerConnection.addTrack() 来把我们的音视讯传送给对方 ...

在 header 带 token 的 Guzzle Http Request 模板

单纯纪录自己用的 Guzzle Request 模板 简单版 use GuzzleHttp\Clie...

Day 1 : 前言+本系列会使用到的东西(vscode、xampp、virtualbox、ubuntu、python安装说明)

前言: 大家好,这是我第一次参加铁人赛 主要是想记录一下自己学过的东西 并和大家分享一些我觉得很重要...

宝塔Linux版升降级7.7版本脚本

复制代码保存*.sh,然后bash *.sh执行 #!/bin/bash PATH=/bin:/sb...