javascript变量的存储

var a = 'hello';
var obj = {
	name: 'obj'
};

js变量分为两种类型:原始类型和引用类型。
原始类型如:Number、string、Boolean、null、undefined。引用类型如:function、array、object
原始类型的大小是固定的,所以为了效率,在栈中分配内存,较快访问。而引用类型由于大小不固定,所以在堆中分配内存.
1.到底两者是怎么分配内存的呢?
JavaScript的执行是这样的,把要执行的函数压入内存栈,为函数内定义的每个变量分配内存,函数执行结束,释放内存。再把下一个要执行的函数压入内存栈
jvascript为原始类型在栈中分配空间,变量:变量的值这种形式;引用类型在栈中定义 ,引用类型变量:引用类型变量值在堆中对应的地址,然后在堆中分配内存。
如下图所示:
001

002

var str = 'test';
var obj = {
	name: 'obj'
};
str = obj;

在javascript里变量的存储包含三个部分:
部分一:栈区的变量标示符;(上述代码的str)
部分二:栈区变量的值;(上述代码的’test’)
部分三:堆区存储的对象。(上述代码的{name: ‘obj’})

2.在javascript里传递参数是按值传递的
javascript里变量复制和函数传参都是在传递栈区的值

看如下代码:

function testFtn(sNm, pObj) {
    console.log(sNm); // new Name
    console.log(pObj.oName); // new obj
    sNm = "change name";
    pObj.oName = "change obj";
}
var sNm = "new Name";
var pObj = {
    oName: "new obj"
};
testFtn(sNm, pObj);
console.log(sNm); // new Name
console.log(pObj.oName); // change obj

变量sNm未被改变,引用类型的变量pObj值被改变了。
为什么呢?
在javascript里变量的复制(函数传参也是变量赋值)本质是传值,这个值就是栈区的值,而基本类型的内容是存放在栈区的值里,所以复制基本变量后,两个变量是独立的互不影响,但是当复制的是引用类型时候,复制操作还是复制栈区的值,但是这个时候值是堆区对象的地址,因为javascript语言是不允许操作堆内存,因此堆内存的变量并没有被复制,所以复制引用对象复制的值就是堆内存的地址,而复制双方的两个变量使用的对象是相同的,因此复制的变量其中一个修改了对象,另一个变量也会受到影响。
下面看个例子:

var ftn1 = function() {
    console.log("test:ftn1");
};
var ftn2 = function() {
    console.log("test:ftn2");
};

function ftn(f) {
    f();  // line2
    f = ftn2; // line3
}
ftn(ftn1); // line1 test:ftn1
console.log("====================华丽的分割线======================");
ftn1(); // line4 test:ftn1

析:
由于JavaScript传值其实是变量复制,是值的传递。
在执行line1时,复制变量ftn1,实际栈中如下:
ftn1值的堆地址 | ftn1值的堆地址
ftn2值的堆地址 | ftn2值的堆地址
ftn1复制f | ftn1值的堆地址
所以执行到line2时,相当于是ftn1复制f的执行,其对应的方法是

function() {
    console.log("test:ftn1");
};

所以输出test:ftn1
执行到line3时,ftn1复制f值被改变,,实际栈中如下:
ftn1值的堆地址 | ftn1值的堆地址
ftn2值的堆地址 | ftn2值的堆地址
ftn1复制f | ftn2值的堆地址
所以ftn1没有被改变
当执行到line4时,输出结果还是test:ftn1
参考文章:
谈谈javascript语法里一些难点问题(一)

此条目发表在JavaScript分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注