简体   繁体   English

Javascript 创建对 object 属性的引用?

[英]Javascript create reference to an object property?

I understand that in javascript, primitives are passed by value and objects are passed by reference .我了解到在 javascript 中, primitives are passed by value and objects are passed by reference

I'm interested in creating a workaround of some kind that would let me get a reference to an object property containing a primitive.我有兴趣创建某种解决方法,让我获得对包含原语的 object 属性的引用。 For example, what I wish would work is:例如,我希望能起作用的是:

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

Of course, this doesn't work.当然,这是行不通的。 I'm aware that you could create a getter and setter function instead, or use one object to reference another object, but what I'd really like is some kind of workaround that allowed me to define a variable as a reference to the property of another object, and so far it seems this just can't be done.我知道你可以创建一个 getter 和 setter function,或者使用一个 object 来引用另一个 object,但我真正想要的是某种解决方法,它允许我定义一个变量作为对属性的引用另一个 object,到目前为止,这似乎无法完成。

So, my question is simply: is this even possible, and if so, how?所以,我的问题很简单:这是否可能,如果可能,如何实现?

Primitive types are immutable, so no, it's not possible. 原始类型是不可变的,所以不,这是不可能的。 You can wrap your primitive type with an object, like this: 您可以使用对象包装基本类型,如下所示:

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 +

OR 要么

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

The React framework uses a very simple pattern to encapsulate values. React框架使用非常简单的模式来封装值。

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

You can pass around the object, the current value can be accessed by inspecting the value property of the object, if you want to change it you can call requestChange with a new value, you can change the value. 您可以传递对象,可以通过检查对象的value属性来访问当前值,如果要更改它,可以使用新值调用requestChange ,您可以更改该值。 The advantage would be to have the actual "storage location" and the logic for changing the value decoupled from the value read and write access. 优点是具有实际的“存储位置”和用于将值与读取和写入访问值分离的逻辑。 Note that the values can also be complex objects. 请注意,值也可以是复杂对象。

You could also achieve something similar with closures: 你也可以用闭包来实现类似的东西:

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

This works because the getter and setter functions have access to whatever bindings were in scope at the time of their creation ( object and prop ). 这是有效的,因为getter和setter函数可以访问创建时范围内的任何绑定( objectprop )。 You can now pass ref around, store it in a data structure, etc. 您现在可以传递ref ,将其存储在数据结构中等。

No, there isn't a nice way to do it. 不,没有一个很好的方法来做到这一点。

You can use a work-around if you want to. 如果您愿意,可以使用解决方法。 Something like wrapping all your primary data types with single element arrays: 像使用单个元素数组包装所有主数据类型的东西:

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

That's less than ideal though, as you have to use [0] to access the property all the time. 但这并不理想,因为你必须使用[0]来一直访问该属性。 There are some cases where it can be useful though, and the default toString of a single element array is just the toString of its element, so you can use the property directly in a string context: 在某些情况下,它可能很有用,并且单个元素数组的默认toString只是其元素的toString ,因此您可以直接在字符串上下文中使用该属性:

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

if you want to "link" or "synchronize" two properties, each of a different object, you could do it like this:如果你想“链接”或“同步”两个属性,每个属性都是不同的 object,你可以这样做:

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}

I don't know how satisfying this is, but you could do it if you were ok with wrapping the desired object in an object like so: 我不知道这是多么令人满意,但如果您可以将所需对象包装在如下对象中,那么您可以这样做:

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

It isn't exactly what you asked for, but it would work. 这不完全是你要求的,但它会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM