发现自己第一次编辑时没有说清楚,特此修改一遍2019.10.28
4.1.3 传递参数
ECMAScript所有函数的参数都是按值传递的,不是按引用传递的
function setName(obj){
obj.name = "yuan";
obj = new Object();
obj.name = "fa";
}
var person = new Object();
setName(person);
console.log(person.name); //yuan
obj = new Object();
obj.name = “fa”;
这两行代码创建了一个新对象和这个新对象下的一个属性,并将其赋值给obj,说明obj以前是指向一个对象的,现在obj指向这个新对象了。
若函数参数是按引用传递的,那么obj.name改变了,person.name也会跟着改变.但是person.name没有改变,说明两者没有指向同一个对象.
图片转自@猪猪女孩zy
obj是变量,在栈里。object是对象,在堆里。
由图可知两者指向堆中的对象是两个不一样的对象
所以函数内的参数就相当于是个局部变量,无论他在函数内怎么折腾,怎么成百上千的重新为其属性引用,都不会影响函数外的对象,
所以函数参数只按值传递,不按引用传递给函数外的对象
我觉得也可以通俗的理解为:
setName(person);调用函数,它走到obj.name = “yuan”;时,已经得到它想要的值了。它就直接走出函数了,因为它只是要一个值而已。即使你后面又改变了obj引用的对象,但这又有什么关系呢?它只是要obj.name的值而已,而不是要obj的引用从而到堆里面去找obj引用的那个对象再去找那个对象的name属性,不是这样的。它只会到栈,不会去栈里面!!!!
.
.
.
栈内存和堆内存的区别(补加)
首先JavaScript中的变量分为基本类型和引用类型。基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象。
1、基本类型
基本类型有Undefined、Null、Boolean、Number 和String。这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的。
2.引用类型
引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象是按引用访问的。如下图所示:栈内存中存放的只是该对象的访问地址,在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把它们保存到栈内存中。但内存地址大小的固定的,因此可以将内存地址保存在栈内存中。 这样,当查询引用类型的变量时, 先从栈中读取内存地址, 然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问当我们看到一个变量类型是已知的,就分配在栈里面,比如INT,Double等。其他未知的类型,比如自定义的类型,因为系统不知道需要多大,所以程序自己申请,这样就分配在堆里面。基本类型大小固定,引用类型大小不固定,分开存放使得程序运行占用内存最小。
3、栈内存:存放基本类型。 堆内存:存放引用类型(在栈内存中存一个基本类型值保存对象在堆内存中的地址,用于引用这个对象。)
4、基本类型在当前执行环境结束时销毁,而引用类型不会随执行环境结束而销毁,只有当所有引用它的变量不存在时这个对象才被垃圾回收机制回收。
引用:https://www.cnblogs.com/wei-dong/p/9674628.html
今天(8.14)发现了个题,跟第四章的作用域有关就写这儿了
问的是会打印出什么
var a = 10;
function foo(){
console.log(a);
var a = 100;
}
foo();
答案是undefined,函数内部有var a = 100;所以声明会提前到函数的最前端,等价于
var a = 10;
function foo(){
var a; //a被声明未被赋值,所以是undefined
console.log(a);
a = 100;
}
foo();
所以打印为undefined
所以可看出函数内定义并赋值var a = 100;实际上是两个有先后顺序的过程,定义var a;在函数的最前面,赋值a = 100;在var a = 100;的位置
延伸:若是函数内没有var a = 100;则直接调用函数外a的值
var a = 10;
function foo(){
console.log(a);
}
foo(); //10