使用私有成员复制 javascript 对象

发布于 2024-09-27 12:29:24 字数 1058 浏览 0 评论 0原文

我环顾四周,没有发现任何可以帮助我的东西。为什么我不能在不使它们量子纠缠的情况下克隆具有私有成员的 javascript 对象?

只要看看这段代码...它是一个带有 getter 和 setter 的普通私有财产。 不知何故,如果我在一个实例上调用公共设置器,克隆的实例也会发生变化。为什么?可以解决吗?

obj = function(){
    var changed = 0;
    this.getChanged = function(){
        return changed;
    }
    this.setChanged = function(){
        changed = 1;
    }
    this.setUnchanged = function(){
        changed = 0;
    }
};

myObj = new obj();
copiedObj = $.extend(true, {}, myObj); // Or any other deep copy function you'd have around

myObj.setChanged();
myObj.getChanged(); // returns 1
copiedObj.getChanged(); // returns 1!
copiedObj.setUnchanged();
copiedObj.getChanged(); // returns 0
myObj.getChanged(); // returns 0

感谢您的任何想法。

编辑:到目前为止,没有什么新内容。我知道 javascript 并不像 Java 或 C++ 那样真正具有面向对象,但是嘿,我们谈论的是编程语言,总有一种出路。有时它很丑陋,但总有一种。

我得到它。 解决方案A:只需将其设置为this.changed,而不是varchanged
解决方案 B:创建我自己的克隆函数来重新构建整个对象

我只是希望有一些解决方案 C 可以将 javascript 欺骗到标准的面向对象模式。

各位,我到底是被A还是B困住了?

I've looked all around and found nothing to help me. Why on earth can't I clone a javascript object with private members without making them quantum entangled?

Just look at this code... It's a plain private property with getter and setter.
Somehow if I call the public setter on one instance, the cloned one gets changed too. Why? Can it be worked around?

obj = function(){
    var changed = 0;
    this.getChanged = function(){
        return changed;
    }
    this.setChanged = function(){
        changed = 1;
    }
    this.setUnchanged = function(){
        changed = 0;
    }
};

myObj = new obj();
copiedObj = $.extend(true, {}, myObj); // Or any other deep copy function you'd have around

myObj.setChanged();
myObj.getChanged(); // returns 1
copiedObj.getChanged(); // returns 1!
copiedObj.setUnchanged();
copiedObj.getChanged(); // returns 0
myObj.getChanged(); // returns 0

Thanks for any ideas.

Edit: So far, nothing new. I know javascript doesn't really have OO like Java or C++, but hey we're talking about programming languages, there is always one way out. Sometimes it's ugly but there is one.

I get it.
Solution A: just make it this.changed instead of var changed
Solution B: make my own clone function that rebuilds the whole object anew

I was just hoping there would be some Solution C that would trick javascript into standard Object Oriented patterns.

Somebody, am I really stuck with A or B?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

探春 2024-10-04 12:29:24

问题是 changed 不是私有变量——JavaScript 没有私有变量。它是您分配给 obj 变量的函数的局部变量。当您创建分配给 getChanged / setChanged / setUnchanged 属性的函数时,您正在创建 闭包,通过变量更改关闭。

当您克隆 myObj 时,您只是为这些函数创建额外的别名。因此,无论您是通过 myObj 还是 copiedObj 访问它们,您仍然会调用相同的函数,并且因为它们是闭包,所以您访问的是完全相同的 <在这两种情况下都改变了变量。由于您无法复制函数,因此最好不要尝试将 changed 设为私有,而只在第二行执行 this.changed = 0;

The problem is that changed isn't a private variable-- JavaScript doesn't have private variables. It's a local variable to the function you assign to the obj variable. When you create the functions that get assigned to the getChanged / setChanged / setUnchanged properties, you're creating closures that are closed over the variable changed.

When you clone myObj, you're just creating additional aliases to those functions. So, you're still calling the same functions regardless of whether you access them through myObj or copiedObj, and because they're closures, you're accessing exactly the same changed variable in both cases. Since you can't copy functions, you're better off not trying to make changed private and just doing this.changed = 0; on the second line.

猫卆 2024-10-04 12:29:24

函数中用作构造函数的局部变量称为“私有成员”,因此 Java 大众可以理解其使用意图。它不像财产那样运作。它是词法作用域中的局部变量。它对于实例而不是类来说是“私有的”。 javascript 中没有类。

最好的选择是添加一个克隆方法来深度复制实例。

Local variables in functions that are used as constructors are called "private members" so Java masses can understand the intention of the usage. It doesn't work like a property. It is a local variable in a lexical scope. It is "private" to the instance, not the class. There are no classes in javascript.

Your best bet is adding a clone method that will deep copy the instance.

白鸥掠海 2024-10-04 12:29:24

即使是深层复制也只能将函数复制为引用。由于您的函数是闭包,因此它们都共享相同的私有成员。为什么不写一个clone()方法呢?

Even a deep copy can't copy a function as anything but a reference. And since your functions are closures, they all share the same private members. Why not write a clone() method?

破晓 2024-10-04 12:29:24

得到答案了。

gilly3的提示有帮助。

我使用的克隆/深度复制功能实际上不是 jQuery 的,而是 一个。 Levy 发布了类似的问题

必须以两种方式调整它才能按我的预期工作。其实原作者在解释中已经指出了方法,但是我第一次读的时候没有明白。
首先,我使用原始对象的构造函数实例化副本,并且
从 for in 循环中过滤掉函数。

这是结果。希望对某人有帮助。

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object (functions are skipped)
    if (obj instanceof Object) {
        var copy = new obj.constructor();
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr) && !(obj[attr] instanceof Function)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

Got the answer.

gilly3's hint helped.

The clone/deep-copy function I was using in fact was not jQuery's but the one A. Levy posted on a similar question.

Had to tweak it in two ways to work as I expected. In fact the original author had pointed out the way in his explanation but I didn't catch it at the time I first read it.
First I instantiated the copy with the original object's constructor and
Filtered out functions from the for in loop.

Here's the result. Hope that helps someone.

function clone(obj) {
    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object (functions are skipped)
    if (obj instanceof Object) {
        var copy = new obj.constructor();
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr) && !(obj[attr] instanceof Function)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文