【发布时间】:2012-04-19 15:49:15
【问题描述】:
我们可以将不可变变量的引用作为函数的参数传递吗?
例子:
var x = 0;
function a(x)
{
x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
【问题讨论】:
-
可以说这是不好的风格,因为您打算使用函数的副作用来引起突变。这会使您的代码更难遵循。
标签: javascript
我们可以将不可变变量的引用作为函数的参数传递吗?
例子:
var x = 0;
function a(x)
{
x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
【问题讨论】:
标签: javascript
由于 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。因此,obj 和x 指代内存中的同一事物。更改obj 的Value 属性会影响x 的Value 属性。
Javascript 将始终按值传递函数参数。这只是语言的规范。您可以在两个函数的本地范围内创建x,并且根本不传递变量。
【讨论】:
这个问题可能会有所帮助: How to pass variable by reference in javascript? Read data from ActiveX function which returns more than one value
总而言之,Javascript 原始类型始终按值传递,而对象内部的值通过引用传递(感谢评论者指出我的疏忽)。所以为了解决这个问题,你必须把你的整数放在一个对象中:
var myobj = {x:0};
function a(obj)
{
obj.x++;
}
a(myobj);
alert(myobj.x); // returns 1
【讨论】:
x 时,无论x 是否是一个对象,您都不能以调用者看到的任何方式将其替换为其他值。
我发现了一种稍微不同的实现指针的方式,从 C 的角度来看,它可能更通用且更容易理解(因此更适合用户示例的格式)。
在 JavaScript 中,就像在 C 中一样,数组变量实际上只是指向数组的指针,因此您可以像声明指针一样使用数组。这样,代码中的所有指针都可以以相同的方式使用,尽管您在原始对象中命名了变量。
它还允许使用两种不同的符号来表示指针的地址和指针的地址。
这里是一个例子(我用下划线表示一个指针):
var _x = [ 10 ];
function foo(_a){
_a[0] += 10;
}
foo(_x);
console.log(_x[0]);
产量
output: 20
【讨论】:
你从窗口对象中引用了“x”
var x = 0;
function a(key, ref) {
ref = ref || window; // object reference - default window
ref[key]++;
}
a('x'); // string
alert(x);
【讨论】:
迟到的答案,但我遇到了一种通过闭包引用传递原始值的方法。创建指针比较复杂,但是可以。
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
【讨论】:
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
【讨论】:
在 JavaScript 中,这将是一个全局的。但是,您的函数看起来更像这样:
function a(){
x++;
};
由于x在全局上下文中,你不需要将它传递给函数。
【讨论】:
这可能是不可能的,因为 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);
【讨论】:
在 JavaScript 中,您不能通过引用函数来传递变量。但是,您可以通过引用传递对象。
【讨论】:
我认为这与 C 或任何带有指针的语言相反:
/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
.
o == o2 // obviously false : not the same address in memory
o <= o2 // true !
o >= o2 // also true !!
这是个大问题:
这意味着您可以列出/管理您的应用程序创建(分配)的每个对象,
从庞大的对象列表中,计算出有关这些对象的一些信息(例如,它们是如何链接在一起的)
但是当您想要检索您创建的关于特定对象的信息时,您无法通过二分法在 巨大列表 中找到它:每个对象没有唯一标识符 可以用来代替真实内存地址
这最终意味着这是一个巨大的问题,如果你想用 javascript 编写:
【讨论】:
JavaScript 不支持通过引用传递原始类型。不过,有一个解决方法。
将所有需要传递的变量放入一个对象中。在这种情况下,只有一个变量x。不要传递变量,而是将变量名作为字符串传递,即"x"。
var variables = {x:0};
function a(x)
{
variables[x]++;
}
a("x");
alert(variables.x);
【讨论】:
根据您的需要,您可以简单地保存变量名称,然后像这样访问它:
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
【讨论】:
window 对象。此外,不建议使用全局变量,因为可能已经有同名变量。
它只是不支持指针,故事结束:-(。
我想补充一点,虽然我是全新的并且来自 C 背景,但根据我正在阅读的有关事件循环和堆栈的内容,您应该尽可能地让任何对象靠近它的调用者。由于我是全新的,我可能有这个错误。
这里的很多答案都建议将其设为全局,但如果我没看错的话,这可能会增加堆栈跳数,并且在某种程度上,可能会不必要地分割您的事件循环(取决于当前被调用的对象是什么)做)。
此外,任何模仿指针的例子,在许多方面都只是做同样事情的 1,它不会是指针。
【讨论】:
我会同意最引用的答案,但请注意'var'参数,使用'let',或者在这种情况下使用'const'更好,因为指针或指向对象不应该改变随时。
const x = {value: 0};
function foo(obj){
++obj.value;
}
foo(x);
alert(x.value);
【讨论】:
在您的示例中,您实际上有 2 个同名变量。 (全局)变量 x 和 作用域 变量 x。有趣的是,当 javascript 选择如何处理 2 个同名变量时,会使用函数范围名称并忽略范围外变量。
假设 javascript 总是以这种方式运行可能是不安全的......
干杯!
【讨论】: