js中数据、内存、变量的概念及三者之间的关系

数据、内存、变量的概念及三者之间的关系

什么是数据

数据就是存储在内存中代表特定信息的东西,这个东西本质上就是许多个0和1组成的

数据的特点

可传递

var a = 123
var b = 123

可运算

var a = 123
a += 1

什么是内存

内存是电脑硬件中的内存条在通电后产生的可以用于储存数据的空间,这些空间是临时的(在断电后空间会消失,数据会丢失)

内存的产生与死亡(生命周期)

内存条 ==> 通电 ==> 产生可以存储数据的内存空间 ==> 储存数据 ==> 处理数据 ==> 断电 ==> 内存空间与数据都消失

每一块内存都有对应的唯一的内存地址值

栈内存

存储着全局变量局部变量等一些基本类型数据

堆内存

储存各种对象

JS引擎如何管理内存

内存的产生与死亡(生命周期)

内存条 ==> 通电 ==> 产生可以存储数据的内存空间 ==> 储存数据 ==> 处理数据 ==> 断电 ==> 内存空间与数据都消失

内存释放的细节

  • 全局变量: 变量申明时产生,浏览器环境关闭后释放
  • 局部变量: 函数调用是产生,函数调用完毕后自动释放,被垃圾回收器回收
  • 对象类型数据: 对象先需要成为垃圾对象,然后在某一时刻(时间很快)被垃圾回收器回收

内存的自动释放,和垃圾回收器回收机制不是同一时刻进行的,即使两者的时刻相差可以忽略不计

什么是变量

变量存储着可以变化的值, 每个变量都对应着一块内存(有内存地址),变量名作为标识可以查找到对应的内存,变量值就是内存中保存的数据

变量是普通类型时

var a = 123
console.log(a)
/* 
    此时的状况是:
        -   栈内存中开辟出了一块保存这个为123的值
        -   变量名a对应着这块保存着123的内存,当然变量名也是在栈内存中的
        -   console.log(a)就是直接读取保存在栈内存中的变量名为a的值,这个值就是123
 */

变量是引用类型时

// obj这个变量保存的是引用类型(对象类型)的数据,所以obj是个引用类型变量
var obj = {
    name: 'Fitz'
}
console.log(obj)
/* 
    此时的状况是:
        -   栈内存中开辟出了一块保存obj这个变量名的内存
        -   堆内存中开辟一块保存着对象的内存,(此时重点说明一下,无论栈内存还是堆内存中的每块内存都有其内存地址值), 对象中保存着'Fitz'这个值
        -   console.log(obj)读取栈内存中obj这个变量名对应的变量值,只不过这个变量值是在堆内存中保存的对象所对应的那块内存的地址值,而不是普通类型变量那样,变量值就是普通类型数据
 */

var obj2 = obj
/* 
    此时的状况是:
        -   将在栈内存中保存的变量名为obj的变量值(内存地址),赋值给obj2
 */

数据、内存、变量的三者之间的关系

  • 内存是用于储存数据的空间
  • 变量是内存的标识,用于找到对应的内存空间,达到读取数据的目的

给函数传递实参时,是值传递还是引用传递

理解1: 都是值传递, 即都是将变量的值作为实参传递给函数的形参

var a = 1
var obj = {name: 'Fitz'}
function func1 (a) {
    a = a + 1
}
function func2 (obj) {
    console.log(obj.name)
    obj = {name: 'Lx'}
    console.log(obj.name)
}

func1(a)
console.log(a)  // 1
func2(obj)              // 'Fitz'  'Lx'
console.log(obj.name)   // 'Fitz'
/* 
    这个例子能说明都是值传递的理由:
        -   在调用函数传递实参时,都是将变量的值(变量a的值, 变量obj的值)传递给函数的形参,只不过这个变量的值分为两种: 
                1. 普通数据类型的变量值就是普通类型数据
                2. 对象类型(引用类型)的变量值是内存地址值(对象在堆内存中的)
 */

/* 
    console.log(obj.name)依然是Fitz的原因:
        -   把obj的值(内存地址值)作为实参赋值给func2的形参(obj)
        -   函数内部执行语句obj = {name: 'Lx'}
        -   重点: 此时函数外部(全局)中的obj仍然指向{name: 'Fitz'}
                  而函数内部(局部)中的obj改变指向{name: 'Lx'}
        -   在函数执行完毕后,形参的这个obj(局部的obj)就会变成垃圾对象准备被垃圾处理器处理
 */

理解2: 既有值传递,又有引用传递, 即变量的值是普通类型数据时是值传递,变量值是对象类型数据时是引用传递

var a = 1                   // 变量值是普通类型数据
var obj = {name: 'Fitz'}    // 变量值是对象类型数据
function func1 (a) {
    a = a + 1
}
function func2 (obj) {
    console.log(obj.name)
    obj = {name: 'Lx'}
    console.log(obj.name)
}

func1(a)                // 此时外部变量a(全局中的a)通过值传递,传递给形参a(局部中的a)
console.log(a)  // 1
func2(obj)              // 'Fitz'  'Lx'     此时将外部变量obj(全局中的obj)的值(内存地址值)传递给形参obj(局部中的obj),这种传递方式叫做引用传递
console.log(obj.name)   // 'Fitz'
原文地址:https://www.cnblogs.com/fitzlovecode/p/jsadvanced.html