2013-02-17 35 views
1

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

因此,示例代码:既卓智和ITwo的的

//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; 

现在“myProperty的”属性等于321,因为“复制”方法返回而不是值的参考。这种行为是预期的,并且一切都很好。现在

,我试图做同样的与本机对象类型,数量。让我们以更面向对象的程序员友好的方式创建它的一个实例:

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

iOne = 321; 

而现在,发生了一些可怕的事情。卓智等于321,但是ITwo的保持它的价值,仍然等于123

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

+0

如果您在最终作业后检查'iOne'的类型,您将看到''number'',但'iTwo'的类型是''Object'' – 2013-02-17 01:28:56

+0

这与本机对象没有任何关系与非本地的。在你的第一个例子中,如果你将'iTwo.myProperty = 321'改为'iTwo = 321',你会发现后者不会影响'iOne';在你的第二个例子中,如果你将'iOne = 321'改为'iOne.myProperty = 321',你会发现后者会影响iTwo。 – ruakh 2013-02-17 01:30:07

回答

1

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

串被当你改变一个字符串,它总是创建一个新的字符串,所以它更像它使得即使以前的分配是一个参考的副本的特殊情况,因为它们是不可变的。

分配:

iOne = 321; 

用简单的原始数字类型替换卓智的值,使之具有任何其他变量没有影响。

+0

似乎你对变量和值很困惑。 Javascript中的数字和数组之间的行为没有实质性区别(数字是不可变的除外)。 – 6502 2013-02-17 01:34:19

+0

@ 6502 - 请显示一个参考,说一个数字是不可变的。 – jfriend00 2013-02-17 01:36:02

+0

尝试:'x = 3; x.y = 12; console.log(x.y);' – 6502 2013-02-17 01:37:53

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

iOne = 321; 

您正在用明显的原始数字覆盖iOne变量所持有的对象引用。

的对象举行的参考,但他们都不是可以直接取消引用指针,所以你不能替换该存储单元保存的数据。你只能改变它(如果对象是可变的)

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

1
iOne = 321; 

此代码做了什么预期,您分配321给变量iOne,覆盖它被引用到最初。

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 protoype模型,并能在某些情况下有用的另一种可能性是创建一个单独的对象,就会出现像浅拷贝可以在不影响原有发生突变,但其不是引用当读取原始对象:

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作为其原型,所以当查找属性(用于阅读)时,如果在q中找不到内容,它将在p内搜索。但是,在写入时,属性将设置在q之内,而不会影响p,并且从那一刻开始,将返回q中的值,而不必在原型链中继续。