在开发中,我们常常混淆数据和变量,其实这是两个相互关联单又不同的概念,想弄清这两个个概念我们还需要从js数据存储时的内存结构来看

  • 数据是什么? 变量是什么? 内存是什么?
  • 数据 :
    在编程语言中数据是存储在内存或硬盘中代表特定信息的。。。东西,它的本质是二进制编码;
    数据的特点是可存储,可修改;
    程序运行的本质是在内存中操作数据;
    我们常说一切皆对象,有它的道理但细究的话也不全面,对象实际上是数据的一种容器,或者说是一系列有关系的数据的集合。我觉的更准确的说法是一切皆数据。
  • 变量:
  • 可变化的量, 由变量名和变量值组成,在js中变量名是字符串类型的
  • 每个变量都对应的一块小内存, 变量名用来查找对应的内存, 变量值就是内存中保存的数据。
  • 变量的值不会是一个对象,引用变量保存的是对象数据的在堆内存中的地址
  • 内存
  • 内存条通电后产生的可储存数据的空间(临时的)
  • 内存产生和死亡: 内存条(电路版)==>通电==>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失
  • 一块小内存的2个数据
  • 内部存储的数据
  • 地址值
  • 内存分类
  • 栈: 存储变量
  • 堆: 存储对象
  • 数据 内存 和变量的关系
  • 内存用来存储数据的空间
  • 变量是内存的标识,js引擎根据这个表示找到并操作内存中的具体数据
  • 两个引用变量指向同一对象数据问题
var obj1 = {a:1};
var obj2 = obj1

此时两个变量指向同一对象,让我们来用其中一个变量操作这个对象

obj1.a = 2;
console.log(obj2.a); //2

结论一:2个引用变量指向同一个对象, 通过一个变量修改对象内部数据, 另一个变量看到的是修改之后的数据

obj1 = {a:3};
console.log(obj2.a); //2

结论二:2个引用变量指向同一个对象, 让其中一个引用变量指向另一个对象, 另一引用变量依然指向前一个对象

这两个结论看似简单,明了但我们很容易就在这上面栽跟头,让我们来看一个进阶应用

可以自己先做一下

 var obj1 = {a:1};
 var obj2 = obj1;

function fun(obj2) {
  obj2 = {a:2};
 }
  fun(obj2);
  console.log(obj2.a)

结果是 1 ,先明确函数内外的obj2是两个不同的变量,在传参时外层obj2将他保存的对象地址传给了内层obj2,此时它们只想同一个对象。之后在函数内部对内层的obj2进行了重新赋值。根据“两个引用变量指向同一个对象, 让其中一个引用变量指向另一个对象, 另一引用变量依然指向前一个对象”,可以得出外层obj2依然执行原来的对象。

  • 传参问题
    上一个案例设计的参数传递问题,尤其是实参为变量时的参数传递,下面我们专门讨论下这个问题
  • 变量为基本变量: 此时的传递方式是值传递,也叫复制传递,变量做参数,传入的并不是变量本身,而是将变量的值复制一份赋给形参
var a = 1; 
 function fun (a){ 
 a = 2; 
 } 
 fun(a); 
 console.log(a); //1;

  • 同样的内部和外部的a,是两个变量,传参是只是将外部a的值复制赋给内部的a,此后两者便没有关联。
  • 变量为引用类型的传递
    有人认为是值传递,有人认为是引用传递。其实都没错,只是说法不同。都是在说传递地址,前者的值说的变量保存的地址值,后者说的是对某一个对象数据的引用,其实说的是一件事。
    更为准确的描述:引用类型变量传递的是该变量中保存的对应对象的内存地址。在传参完成后实参和形参就是两个指向同一对象的变量。
  • 变量和数据的生命周期
  • 前置知识:
  • 1变量分局部变量和全局变量
  • 2变量占用栈内存空间
  • 3对象数据保存在堆内存中

函数执行完(函数的执行上下文出栈)后,它的局部变量占用栈内存会被释放(不考虑闭包)

全局变量占用的栈内存永远不会释放,引文全局的执行上下文始终在栈中(不会出栈)

引用变量所指向的对象数据,当不存在变量指向它时,会被释放

举一个简单但很能说明问题的例子

function fun(){
    var a = {b:1}
}
fun();

函数fun入栈—>栈内存开辟一块空间给a变量—>堆空间开辟一块空间给对象{b:1},并把这块空间的地址保存在a变量中—>**fun出栈—>**a占用的栈内存自动释放—>没有变量指向{b:1}对象,该对象占用的空间被回收