【问题标题】:Javascript create reference to an object property?Javascript创建对对象属性的引用?
【发布时间】:2014-05-12 04:27:00
【问题描述】:

我知道在 javascript 中,primitives are passed by value and objects are passed by reference

我有兴趣创建某种解决方法,让我获得对包含原语的对象属性的引用。例如,我希望工作的是:

var someObject = {a: 1, b: 2};
var myRef = someObject.b;
myRef ++;
someObject.b #=> 3

当然,这是行不通的。我知道您可以创建一个 getter 和 setter 函数,或者使用一个对象来引用另一个对象,但我真正想要的是某种解决方法,它允许我将变量定义为对属性的引用另一个对象,到目前为止,这似乎无法完成。

所以,我的问题很简单:这是否可能,如果可以,如何实现?

【问题讨论】:

  • 你尝试的方法,只适用于可变对象。
  • 所以,我明白了,但似乎您设置为属性或变量的任何内容至少有一个指向它的引用......所以看起来应该有一些创建对引用的引用而不是对值的引用的方法......我想这不是 JS 的工作方式,但目前我还不清楚为什么。
  • 您只能在javascript中获取对对象或数组的引用。因此,获取对其他类型的引用的唯一方法是将其放入对象或数组中并传递/分配包含对象或数组。这就是 JS 的工作原理。
  • 可能没有什么好的方法可以做到这一点,即使有解决方法,您也可能不应该使用它,因为它有点破坏了通过“复制引用”传递的意义(javascript 确实通过引用传递)。
  • @Andrew 您正在增加一个数字,该数字是不可变的。因此,在递增之后,将创建一个具有递增值的新不可变对象,并且引用 myRef 将引用该新创建的对象。所以,无论如何你都会失去旧的参考。

标签: javascript variables reference


【解决方案1】:

原始类型是不可变的,所以不,这是不可能的。你可以用一个对象来包装你的原始类型,像这样:

function MyNumber(n) { this.n = n; }
MyNumber.prototype.valueOf = function() { return this.n; }
var someObject = { a: 1, b: new MyNumber(2) };
var myRef = someObject.b;
MyNumber.call(myRef, myRef + 1);
console.log(+someObject.b); // convert to number with +

var someObject = {
    a: { value: 1 },
    b: { value: 2 },
};
var myRef = someObject.b;
my_inc(myRef); // function my_inc (obj) { obj.value++; }
// someObject.b.value == 3

React 框架使用一种非常简单的模式来封装值。

function Link(value, requestChange)
{
    this.value = value;
    this.requestChange = requestChange;
}

您可以传递对象,可以通过检查对象的 value 属性来访问当前值,如果要更改它可以调用 requestChange 使用新值,您可以更改该值。优点是具有实际的“存储位置”和更改值的逻辑与值读取和写入访问分离。请注意,这些值也可以是复杂对象。

你也可以用闭包实现类似的东西:

var someObject = {
    a: 1,
    b: 2
};

function property(object, prop) {
    return {
        get value () {
            return object[prop]
        },
        set value (val) {
            object[prop] = val;
        }
    };
}

var ref = property(someObject, "b");
ref.value; // 2
++ref.value; // 3
someObject.b; // 3

这是可行的,因为 getter 和 setter 函数可以访问它们创建时范围内的任何绑定(objectprop)。您现在可以传递ref,将其存储在数据结构中,等等。

【讨论】:

  • 是的,我认为这是必要的。它在语法上不如创建快捷方式引用那么好,但没关系。感谢您的示例!
【解决方案2】:

不,没有很好的方法。

如果您愿意,可以使用变通方法。类似于用单元素数组包装所有主要数据类型:

var someObject = {a: [1], b: [2]};
var myRef = someObject.b;
myRef[0]++;
someObject.b[0]; // 3

但这并不理想,因为您必须始终使用 [0] 才能访问该属性。但在某些情况下它可能很有用,单个元素数组的默认 toString 只是其元素的 toString,因此您可以直接在字符串上下文中使用该属性:

console.log('My value: ' + someObject.b); // 'My value: 3'

【讨论】:

    【解决方案3】:

    如果你想“链接”或“同步”两个属性,每个不同的对象,你可以这样做:

    var someObject = {
        a: 1,
        b: 2
    };
    var linkedObject = {
        a:1, 
        b:2
    }
    function property(object, prop) {
        return {
            get value () {
                return object[prop]
            },
            set value (val) {
                object[prop] = val;
            }
        };
    }
    var s_prop = 'b'
    var o_ref = property(someObject, s_prop);
    var tmp = linkedObject[s_prop]; 
    
    Object.defineProperty(
        linkedObject,
        s_prop,
        {
    
            set: function(value) {
                o_ref.value = value;
            },
            get: function() {
                return o_ref.value
            }
        }
    );
    linkedObject[s_prop] = tmp 
    
    someObject.b = 333 /// linkedObject.b is also 333 now
    console.log(someObject.b) //  333 
    console.log(linkedObject.b)// 333
    
    linkedObject.b = {"test": 2}
    console.log(someObject.b) //  {test:2}
    console.log(linkedObject.b)// {test:2}
    
    someObject.b.test = 3 
    console.log(someObject.b) // {test:3}
    console.log(linkedObject.b)//{test:3}
    

    【讨论】:

      【解决方案4】:

      我不知道这有多令人满意,但是如果您可以将所需的对象包装在这样的对象中,您可以这样做:

      var a = {a:{a:1},b:2};
      var b = a.a;
      b.a++;
      a.a.a //=> 2
      

      这不是您所要求的,但它会起作用。

      【讨论】:

      • 使用这个逻辑你可以做someObject.b++,但这不是重点
      • 我想我在想你可以在函数指针中使用它,就像@gotnull 的答案一样。所以 fptr(a.a) 可以根据需要更改您的 a.a.a。
      猜你喜欢
      • 2012-03-13
      • 1970-01-01
      • 2014-09-24
      • 2012-06-10
      • 1970-01-01
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多