ECMAScript变量 - 传递参数 (高频面试点)

523 阅读4分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

ECMAScript中所有函数的参数都是按值传递的。这意味着函数外的值会被复制到函数内部的参数中,就像从一个变量复制到另一个变量一样。

如果是原始值,那么就跟原始值变量的复制一样,如果是引用值,那么就跟引用值变量的复制一样.对很多开发者来说,这一块可能会很不好理解,毕竟变量有按值和按引用访问,而传惨则只有按值传递。

在按值传递参数时,值会被复制到一个局部变量(即一个命名参数,或者用ECMAScript的话说,就是argument对象中的一个槽位)。在按引用传递参数时,值在内存中的位置会被保存在一个局部变量,这意味着对本地变量的修改会反映到函数外部。(这在ECMAScript中是不可能的。)

来看下面这个例子:

function addTen(num) {
    num += 10
    return num
}
let count = 20
const result = addTen(count)
console.log(count)  // 20 没有变化
console.log(result) // 30

这里,函数addTen()有一个参数num,它其实是一个局部变量。在调用时,变量count作为参数传入.count的值是20,这个值被复制到参数num以便在addTen()内部使用。在函数内部,参数num的值被加上了10,但这不会影响函数外部的原始变量count。参数num和变量count互不干扰,它们只不过碰巧保存了一样的值。如果num是按引用传递的,那么count的值也会被修改为30.这个事实在使用数值这样的原始值时是非常明显的。但是,如果变量中传递的是对象,就没那么清楚了。

比如,再看这个例子:

function setName(obj) {
    obj.name = '何小生'
}
let person = new Object()
setName(person)
console.log(person.name)  // '何小生'

这一次,我们创建了一个对象,并把它保存在变量person中。然后,这个对象被传给setName()方法,并被复制到参数obj中。在函数内部,objperson都指向了同一个对象。结果就是,即使对象是按值传进函数的,obj也会通过引用访问对象。当函数内部给obj设置了name属性时,函数外部的对象也会反映这个变化,因为obj指向的对象保存在全局作用域的堆内存上。很多开发者错误地认为,当在局部作用域中修改而变化反映到全局时,就意味着参数是按引用传递的。为证明对象是按值传递的,我们再来看看下面这个修改后的例子。 例子:

function setName(obj) {
    obj.name = '何小生'
    obj = new Object()
    obj.name = '小生'
}
let person = new Object()
setName(person)
console.log(person.name)   // '何小生'

这个例子前后唯一的变化就是setName()中多了两行代码,将obj重新定义为一个有着不同name的新对象。当person传入setName()时,其name属性被设置为何小生。然后变量obj被设置为一个新对象且name属性被设置为小生。如果person是按引用传递的,那么person应该自动将指针改为指向name小生的对象。可是,当我们再次访问person.name时,它的值时何小生。这表明函数中参数的值改变之后,原始的引用仍然没变。当obj在函数内部被重写时,它变成了一个指向本地对象的指针。而那个本地对象在指向函数结束时就被销毁了。

注意:ECMAScript中函数的参数就是局部变量

总结小例子:

//数组
function setArray(arr) {
    arr[0] = 1;
    var arr = new Array(); //这里的地址改变了
    arr[0] = 6;
    return arr;
}

var lastArr = new Array();
lastArr[0] = 0;
var newArr = setArray(lastArr);
console.log(lastArr[0] + '|' + newArr[0]); // 1|6

//对象
function setNameAgain(obj) {
    obj.name = 'aaa';
    var obj = new Object(); // 如果是按引用传递的,此处传参进来obj应该被重新引用新的内存单元
    obj.name = 'ccc';
    return obj;
}

var person = new Object();
person.name = 'bbb';
var newPerson = setNameAgain(person);
console.log(person.name + ' | ' + newPerson.name); //aaa | ccc

在向参数传递基本类型的时候,被传递的值会被复制给一个局部变量(arguments对象中的一个元素)。

在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部!

重点时需要搞清楚引用类型的地址与指向地址的指针!!!

最后

公众号:小何成长,佛系更文,都是自己曾经踩过的坑或者是学到的东西

有兴趣的小伙伴欢迎关注我哦,我是:何小玍。 大家一起进步鸭