Javascript基础系列之求值策略

前言

本文翻译自evaluation-strategy

按值传递

参数的值是调用者(caller)传递的对象值的拷贝,函数内部改变参数的值不会影响到函数外部的对象。一般来说,通过重新分配内存(这里不关注重新分配内存是如何实现的 -- 可以是堆栈或动态内存分配的方式),将外部对象的值拷贝到新分配的内存,并用于函数内部的计算

但是,如果参数不是原始值,而是一个负复杂的对象,将带来很大的性能问题,C++就有这个问题,将结构作为值传进函数的时候 —— 就是完整的拷贝

按引用传递

按引用传递接收的不是值的拷贝,而是对象的隐式引用,也就是该对象在外部的直接引用地址。函数内部对参数的任何改变都是影响该对象在函数外部的值,因为两者引用的是同一个对象,也就是说:这时候参数就相当于外部对象的一个别名

按共享传递

该策略的要点是:函数接收的是对象引用的拷贝,该引用拷贝和形参以及其值相关联

这里出现的引用,我们不能称之为“按引用传递”,因为函数接收的参数不是直接的对象别名,而是该引用地址的拷贝

最重要的区别就是:函数内部给参数重新赋新值不会影响到外部的对象(按引用传递会改变)。但是,由于形参拥有地址拷贝,和外部指向同一个对象(也就是说,外部对象并不是像按值传递那样完整拷贝),改变参数对象的属性值将会影响到外部的对象。

ECMAScript中就是按共享传递的

ECMAScript中实现

var foo = {x: 10, y: 20};
var bar = foo;

alert(bar === foo); // true

bar.x = 100;
bar.y = 200;

alert([foo.x, foo.y]); // [100, 200]

即两个标识符(名称绑定)绑定到内存中的同一个对象, 共享这个对象:

foo value: addr(0xFF) => {x: 100, y: 200} (address 0xFF) <= bar value: addr(0xFF)

而重新赋值分配,绑定是新的对象标识符(新地址),而不影响已经先前绑定的对象 :

bar = {z: 1, q: 2};

alert([foo.x, foo.y]); // [100, 200] – 没改变
alert([bar.z, bar.q]); // [1, 2] – 但现在引用的是新对象

即现在 foo 和 bar,有不同的值和不同的地址:

foo value: addr(0xFF) => {x: 100, y: 200} (address 0xFF)
bar value: addr(0xFA) => {z: 1, q: 2} (address 0xFA)

再强调一下,这里所说对象的值是地址,而不是对象结构本身,将变量赋值给另外一个变量 —— 是赋值值的引用。因此两个变量引用的是同一个内存地址。下一个赋值却是新地址,是解析与旧对象的地址绑定,然后绑定到新对象的地址上,这就是和按引用传递的最重要区别

你可能感兴趣的:(Javascript基础系列之求值策略)