JavaScript 如何创建引用

5
你能提供任何解决方案来使用闭包或其他技巧实现对变量的引用吗?
createReference = function() {
    // TODO: how to implement?
};

var x = 5;
var refX = createReference(x); // could be any parameters needed to implement the logic
x = 6;
alert(refX()); // should alert 6

如果将上下文作为第一个参数传递,并传递变量名称(以字符串形式),然后在预定义的上下文中评估该引用,这种方法可行吗?

以下是更完整的场景:

createReference = function(context, prop) {
    return function() {
        return context[prop];
    };
};

Provider = function() {
};
Provider.prototype.x = 5;
Provider.prototype.getXRef = function() {
    return createReference(this, 'x');
};
Provider.prototype.incrementX = function() {
    this.x = this.x + 1;
};

var provider = new Provider();
var refX = provider.getXRef();
provider.incrementX();
alert(refX());

1
将来请不要在代码中嵌入评论提问问题,这会使问题难以看到,并且您有可能被认为这不是一个问题而被关闭。 - Oded
我很高兴回答了你的问题,但在你更新的情况下,为什么不直接使用:Provider.prototype.getXRef = function () { var that = this; return function() { return that.x; }; }; 这样就可以避免使用字符串了。 - brianpeiris
createReference是一种通用的技巧,我可以在不同的情况下使用这种通用方式。对于你的评论:可能没有Provider.prototype.getXRef方法,但在其他某些方法中,我可能想将引用作为回调参数传递给其他对象等等... 在日常使用中,编写createReference(this,'x')然后是function(){var that=this;return function(){return that.x;};}会更易读。 - Mike
我明白了。请看一下我回答的最新编辑,那里有一个更通用的解决方案。我真的认为你应该避免使用字符串,但这取决于你自己 :) - brianpeiris
5个回答

8

你需要使用变量名的字符串,但我认为这是在JavaScript中你所能接近的:

var createReference = function (context, prop) {
  return function () { return context[prop]; };
};

var x = 5;
var refX = createReference(this, 'x');
x = 6;

alert(refX()); // alerts 6

编辑:

在您更新的情况下,最好直接使用闭包,这样您就不必使用变量名称的字符串:

var createReference = function (context, func) {
    return function () { return func.call(context); }
};

Provider = function() {
};
Provider.prototype.x = 5;
Provider.prototype.getXRef = function() {

    return createReference(this, function () { return this.x; });

    // OR if you happen to be running in a 
    // JavaScript 1.8 environment like Firefox 3+,
    // you can use "expression closures" for more
    // concise code:

    // return createReference(this, function () this.x);
};
Provider.prototype.incrementX = function() {
    this.x = this.x + 1;
};

var provider = new Provider();
var refX = provider.getXRef();
provider.incrementX();
alert(refX()); // alerts 6

是的,这些都是不错的替代方案。但是无论如何JavaScript都不是类型安全的,因此在名称误用时不会出现“编译时”错误,因此我认为更好的方法是使用更短、更易读(对我来说)的代码方法,而不是使用字符串的方法。 - Mike

4
在JavaScript中,你无法通过引用传递原始值(数字、字符串等)。然而,每个对象你传递时都会被作为引用传递。(这包括数组)
以你的例子为例:
var foo = { x: 5 };
var refFoo = foo;

// foo.x => 5
// refFoo.x => 5

foo.x = 6;

// foo.x => 6
// refFoo.x => 6

有没有办法使用 new Number(4) 来实现这个?那是一个对象。你能否重新设置它的值以“保持其活性”并将其传递吗?类似于 n=new Number(4); n2=n; n2.setValue(7); alert(n); - Rudie
是的,那将是一个对象。从技术上讲,JS中几乎所有的东西都是对象。然而,标量值(数字、字符串等)根本不会被引用传递,这只是JS的工作方式。 - Dominic Barnes
我知道它是一个对象,但是如何更改Number对象的值呢?.setValue不存在,而且您不能重新分配一个新对象,因为那样会失去对n的引用。以下方法都不可行:n2=7;n2=new Number(7);n2.setValue(7);。前两个会失去引用,第三个不存在。如何更改数字对象的值? - Rudie

0

只有非标量类型可以作为引用传递,并且始终会作为引用传递:

var reference = {};
my_function(reference);
console.log(reference); // will show property - a property value

function my_function(my_reference) {
    my_reference.property = "a property value";
}

var not_a_reference = [];
my_function(not_a_reference);
console.log(not_a_reference); // will NOT show 'a value'

function my_function() {
    my_reference.push("a value");
}

更接近你的例子:

function show(value) {
    alert(value.data);
}

var value = { 'data': 5 };
show(value); // alerts 5
value.data = 6;
show(value); // alerts 6

0

由于对象始终是静态引用,因此您可以这样做:

var o = {};
o.x = 5;
var oRef = o;
alert(oRef.x); // -> 5
o.x = 6;
alert(oRef.x); // -> 6

0

你不能仅仅将x提升为一个引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接