87

我们可以将不可变变量的引用作为函数的参数传递吗?

例子:

var x = 0;
function a(x)
{
    x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
4

15 回答 15

152

由于 JavaScript 不支持通过引用传递参数,因此您需要将变量设为对象:

var x = {Value: 0};

function a(obj)
{
    obj.Value++;
}

a(x);
document.write(x.Value); //Here i want to have 1 instead of 0

在这种情况下,x是对对象的引用。当x传递给函数a时,该引用被复制到obj. 因此,objx在内存中引用相同的内容。更改 的Value属性obj会影响 的Value属性x

Javascript 将始终按值传递函数参数。这只是语言的规范。您可以x在两个函数的本地范围内创建,并且根本不传递变量。

于 2012-04-19T15:53:56.617 回答
19

这个问题可能会有所帮助: 如何在 javascript 中通过引用传递变量?从返回多个值的 ActiveX 函数中读取数据

总而言之,Javascript 原始类型始终按值传递,而对象内部的值通过引用传递(感谢评论者指出我的疏忽)。所以为了解决这个问题,你必须把你的整数放在一个对象中:

var myobj = {x:0};

function a(obj)
{
    obj.x++;
}

a(myobj);
alert(myobj.x); // returns 1

  

于 2012-04-19T15:52:56.603 回答
14

我发现了一种稍微不同的实现指针的方式,从 C 的角度来看,它可能更通用且更容易理解(因此更适合用户示例的格式)。

在 JavaScript 中,就像在 C 中一样,数组变量实际上只是指向数组的指针,因此您可以像声明指针一样使用数组。这样,代码中的所有指针都可以以相同的方式使用,尽管您在原始对象中命名了变量。

它还允许使用两种不同的符号来表示指针的地址和指针地址处的内容。

这是一个示例(我使用下划线表示指针):

var _x = [ 10 ];

function foo(_a){
    _a[0] += 10;
}

foo(_x);

console.log(_x[0]);

产量

output: 20
于 2014-01-19T21:21:55.243 回答
8

您从窗口对象中引用“x”

var x = 0;

function a(key, ref) {
    ref = ref || window;  // object reference - default window
    ref[key]++;
}

a('x');                   // string
alert(x);
于 2014-12-23T15:45:51.470 回答
4

迟到的答案,但我遇到了一种通过闭包引用传递原始值的方法。创建指针相当复杂,但它可以工作。

function ptr(get, set) {
    return { get: get, set: set };
}

function helloWorld(namePtr) {
    console.log(namePtr.get());
    namePtr.set('jack');
    console.log(namePtr.get())
}

var myName = 'joe';
var myNamePtr = ptr(
    function () { return myName; },
    function (value) { myName = value; }
);

helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack

在 ES6 中,可以缩短代码以使用 lambda 表达式:

var myName = 'joe';
var myNamePtr = ptr(=> myName, v => myName = v);

helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack
于 2015-06-29T17:49:46.030 回答
3

Javascript 应该只是将指针放入混合中,因为它解决了很多问题。这意味着代码可以引用未知变量名称或动态创建的变量。它还使模块化编码和注入变得容易。

这是我认为在实践中最接近 c 指针的内容

在js中:

var a = 78;       // creates a var with integer value of 78 
var pointer = 'a' // note it is a string representation of the var name
eval (pointer + ' = 12'); // equivalent to: eval ('a = 12'); but changes value of a to 12

在 c 中:

int a = 78;       // creates a var with integer value of 78 
int pointer = &a; // makes pointer  to refer to the same address mem as a
*pointer = 12;   // changes the value of a to 12
于 2016-02-21T16:45:32.963 回答
1

在 JavaScript 中,这将是一个全局的。但是,您的函数看起来更像这样:

function a(){
   x++;
};

由于x是在全局上下文中,因此您不需要将其传递给函数。

于 2012-04-19T15:53:28.557 回答
1

这可能是不可能的,因为 JavaScript 没有 Perl 的“\”运算符来通过引用获取原语,但是有一种方法可以使用这种模式为原语创建一个“有效的指针”对象。

当您已经拥有原语时,此解决方案最有意义(因此您不能再将其放入对象中而无需修改其他代码),但仍需要将指针传递给您的代码的其他部分以进行修补及其状态;所以你仍然可以使用像指针一样的无缝代理来修改它的状态。

var proxyContainer = {};

// | attaches a pointer-lookalike getter/setter pair
// | to the container object.
var connect = function(container) {
    // | primitive, can't create a reference to it anymore
    var cant_touch_this = 1337;

    // | we know where to bind our accessor/mutator
    // | so we can bind the pair to effectively behave
    // | like a pointer in most common use cases.
    Object.defineProperty(container, 'cant_touch_this', {
        'get': function() {
            return cant_touch_this;
        },                
        'set': function(val) {
            cant_touch_this = val;
        }
    });
};

// | not quite direct, but still "touchable"
var f = function(x) {
    x.cant_touch_this += 1;
};

connect(proxyContainer);

// | looks like we're just getting cant_touch_this
// | but we're actually calling the accessor.
console.log(proxyContainer.cant_touch_this);

// | looks like we're touching cant_touch_this
// | but we're actually calling the mutator.
proxyContainer.cant_touch_this = 90;

// | looks like we touched cant_touch_this
// | but we actually called a mutator which touched it for us.
console.log(proxyContainer.cant_touch_this);

f(proxyContainer);

// | we kinda did it! :)
console.log(proxyContainer.cant_touch_this);
于 2017-01-29T18:07:33.870 回答
0

在 JavaScript 中,您不能通过引用函数来传递变量。但是,您可以通过引用传递对象。

于 2012-04-19T15:55:23.683 回答
0

JavaScript 不支持通过引用传递原始类型。不过,有一个解决方法。

将您需要传递的所有变量放入一个对象中。在这种情况下,只有一个变量x. 不要传递变量,而是将变量名作为字符串传递,即"x".

var variables = {x:0};
function a(x)
{
    variables[x]++;
}
a("x");
alert(variables.x);

于 2016-06-06T15:22:41.037 回答
0

它只是不支持指针,故事结束:-(。

我想补充一点,虽然我是全新的并且来自 C 背景,但从我正在阅读的有关事件循环和堆栈的内容来看,您应该将任何对象尽可能靠近其调用者。由于我是全新的,我可能有这个错误。

这里的很多答案都建议让它成为全局的,但如果我没看错的话,这可能会增加堆栈跳数,并且在某种程度上,可能会不必要地分割你的事件循环(取决于被调用对象当前正在做什么)。

此外,任何模仿指针的示例在许多方面都只是 1 来做同样的事情,这不会是指针。

于 2018-12-14T16:09:29.493 回答
0

我认为这与 C 或任何带有指针的语言相反:

/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
  • 显然在javascript中你不能访问内存中的对象oo2地址
  • 但是您也无法比较它们的地址:(对它们进行排序,然后通过二分法访问)

.

o == o2 // obviously false : not the same address in memory
o <= o2 // true !
o >= o2 // also true !!

这是一个大问题:

  • 这意味着您可以列出/管理应用程序创建(分配)的每个对象,

  • 庞大的对象列表中,计算一些关于这些对象的信息(例如,它们是如何链接在一起的)

  • 但是当您想检索您创建的有关特定对象的信息时,您无法通过二分法在庞大的列表中找到它:每个对象没有唯一标识符可以用作实际内存地址的替换

这最终意味着这是一个巨大的问题,如果你想用 javascript 编写:

  • 一个javascript调试器/IDE
  • 特别优化的垃圾收集器
  • 数据结构抽屉/分析器
于 2015-10-20T23:20:52.510 回答
0

根据您想做的事情,您可以简单地保存变量名称,然后稍后访问它,如下所示:

function toAccessMyVariable(variableName){
  alert(window[variableName]);
}

var myFavoriteNumber = 6; 

toAccessMyVariable("myFavoriteNumber");

要应用于您的特定示例,您可以执行以下操作:

var x = 0;
var pointerToX = "x";

function a(variableName)
{
    window[variableName]++;
}
a(pointerToX);
alert(x); //Here I want to have 1 instead of 0
于 2017-03-05T17:43:36.210 回答
0

我同意最引用的答案,但请注意'var'参数,使用'let',或者在这种情况下使用'const'更好,因为指针或指向对象不应该随时更改。

const x = {value: 0};

function foo(obj){
  ++obj.value;
}

foo(x);
alert(x.value);
于 2022-01-03T12:03:50.343 回答
-1

在您的示例中,您实际上有 2 个具有相同名称的变量。(全局)变量 x 和函数作用域变量 x。有趣的是,当 javascript 选择如何处理 2 个同名变量时,它使用函数范围名称并忽略超出范围的变量。

假设 javascript 总是以这种方式运行可能是不安全的......

干杯!

于 2015-07-06T23:00:36.783 回答