1

最近我开始学习 JavaScript 中的面向对象编程。我的理解是,当引用变量时,我们实际上引用的不是它们的实际值,而是内存中的位置。这就是为什么所有那些应该复制实例的“返回这个”方法都不起作用的原因。

所以,示例代码:

//An example object with a simple property and
//failing "copy" function.
function MyObject()
{
    this.myProperty = 123;
    this.copy = function() { return this; };
}

var iOne = new MyObject();
var iTwo = iOne.copy();
iTwo.myProperty = 321;

现在 iOne 和 iTwo 的“myProperty”属性都等于 321,因为“copy”方法返回了一个引用,而不是一个值。这种行为是意料之中的,一切正常。

现在,我尝试对原生对象类型 Number 执行相同的操作。让我们以更面向对象的程序员友好的方式创建它的一个实例:

var iOne = new Number(123);
var iTwo = iOne; //Equals "iTwo = iOne.copy()", except there isn't a copy method

iOne = 321;

而现在,可怕的事情发生了。iOne 等于 321,但 iTwo 保持其值,仍然等于 123。

我不知道这种行为是由什么引起的。也许 Number 是某种“特殊”?也许与它相关的十进制数不仅仅是一个属性?或者也许它只是为了让没有经验的程序员的生活更轻松?最后一个选项与运算符有关。如果有人对此有所了解,请不要让我理解 JavaScript 的方式崩溃。

4

4 回答 4

1

对象、数组和字符串是通过引用(而不是通过副本)分配的。所有其他类型在分配时都是有效的副本(例如,它们创建一个与旧变量无关的新变量)。

字符串是一种特殊情况,因为它们是不可变的,因此当您更改字符串时,它总是会创建一个新字符串,因此即使之前的赋值是引用,它的行为更像是复制。

分配:

iOne = 321;

正在用简单的原始数字类型替换 iOne 的值,因此它不会对任何其他变量产生影响。

于 2013-02-17T01:27:27.027 回答
1
var iOne = new Number(123);
var iTwo = iOne; //Equals "iTwo = iOne.copy()", except there isn't a copy method

iOne = 321;

iOne您正在用不同的原始编号覆盖变量持有的对象引用。

这些对象作为引用保存,但它们不是可以直接取消引用的指针,因此您无法替换该内存位置中保存的数据。你只能改变它(如果对象是可变的)

具体来说,Number对象包装器是不可变的,或者至少它持有的原始值不能被替换。您只能替换整个对象。

于 2013-02-17T01:28:13.880 回答
1
iOne = 321;

该代码完成了预期的操作,您分配321给变量iOne,覆盖了它最初引用的内容。

于 2013-02-17T01:28:26.870 回答
1

“本机类型”和 Javascript 中的对象之间的行为没有真正的区别(除了本机类型是不可变的)。

在您的第二个示例中,您只是更改了变量iOne指向的内容,为什么要更改另一个自iTwo变量指向的内容?

在第一种情况下,您有两个变量指向同一个对象,如果您使用一个变量来改变对象,您也可以使用另一个变量观察变化(显然......它指向同一个对象)。

在 Javascript 中,你可以想象一切都是引用而不是值(副本)。如果你想复制一些你需要明确地做的事情......对于数组,你可以用来制作;x.slice()的浅拷贝 x对于对象,没有原始函数可以执行相同操作,因此您必须调用构造函数。

一个常见的 OOP 模式是有一个.clone()返回副本的成员函数,因此需要副本的人不需要知道如何制作每个类的副本。

function P2d(x, y) {
    this.x = x;
    this.y = y;
}

P2d.prototype.clone = function() {
    return new P2d(this.x, this.y);
}

另一种特定于 Javascript 原型模型且在某些情况下可能有用的可能性是创建一个单独的对象,该对象看起来像一个浅副本,可以在不影响原始副本的情况下进行变异,但在读取时引用原始对象:

function fakeCopy(x) {
    function f() { }
    f.prototype = x;
    return new f;
}

p = new P2d(10, 20);
q = fakeCopy(p);
console.log(q.x); // Displays 10
q.y = 30;
console.log(q.y); // Displays 30
console.log(p.y); // Displays 20 -- original not changed
p.x = 99;
console.log(q.x); // Displays 99 (!)

发生这种情况是因为 Javascript 对象有一个“原型链”,在访问成员进行读取时会对其进行搜索。q被创建为一个空对象,并以其原型为原型,因此在查找属性(用于读取)时,如果在内部找不到某些东西p,它将在内部进行搜索。但是,在编写时,将在内部设置一个属性,不会影响并且从那时起,将返回存在于中的值,而不必在原型链中上升。pqqpq

于 2013-02-17T01:36:27.007 回答