首页 > JS中的引用传递问题

JS中的引用传递问题

现在遇到一个引用传递的问题,用代码说明吧

var Lan = function(){};
var Attr1 = function(){
    this.name = 'attr1';
}
var Attr2 = function(){
    this.name = 'attr2';
}

Lan.prototype.attr = new Attr1();

var lan = new Lan();
var obj = lan.attr;//这一步不应该是传递的Lan原型链上的引用吗
console.log(obj1);//输出Attr1 {name: "attr1"}

Lan.prototype.attr = new Attr2();//Lan原型链的属性改变,指向Attr2的对象,那obj不也应该指向Attr2的对象?
console.log(obj);//输出Attr1 {name: "attr1"},但结果却不是这样



var Lan = function(){};
var Attr1 = function(){
    this.name = 'attr1';
}
var Attr2 = function(){
    this.name = 'attr2';
}

Lan.prototype.attr = new Attr1();

var lan = new Lan();
var obj = lan.attr;//这一步不应该是传递的Lan原型链上的引用吗   [1]
console.log(obj1);//输出Attr1 {name: "attr1"}

Lan.prototype.attr = new Attr2();//Lan原型链的属性改变,指向Attr2的对象,那obj不也应该指向Attr2的对象?   [2]
console.log(obj);//输出Attr1 {name: "attr1"},但结果却不是这样 , [3]

[1]obj 和 Lan.prototype.attr 同时指向 new Attr1() 创建的对象
[2]Lan.prototype.attr重指向 new Attr2()创建的对象,而obj 指向的对象没有变(new Attr1() 创建的对象没有消失,内存中依旧存在)
[3]obj 指向的对象指向的还是原来的对象


最后如果你console.log(lan.attr),那结果就是Attr2 {name: "attr2"},因为你obj还是指的那个对象。
相当于b = 1;a = b;b = 2;这时,a的value为1,而不是2


一、obj 和 lan 原型对象 attr 属性同时指向 object { name: 'attr1' }

二、obj 依旧指向 object { name: 'attr1' }; lan 原型上的 attr 指向 object { name: 'attr2' }


Javascript中的赋值策略 不仅仅是 按值传递、按引用传递 这么简单;
看一个在 stackoverflow 上的回答:Javascript by reference vs. by value:

  1. Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
  2. Changing the value of a variable never changes the underlying primitive or object, it just points the variable to a new primitive or object.
  3. However, changing a property of an object referenced by a variable does change the underlying object.

再来看段代码:

javascriptfunction changeStuff(num, obj1, obj2){
  num = num * 10;
  obj1.item = "changed";//只是修改obj1的一个属性
  obj2 = {item: "changed"};//修改了obj2这个对象
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num);//10
console.log(obj1.item);// "changed"
console.log(obj2.item);// "unchanged"

以上为Javascript中赋值会遇到的一些情况,有点偏题了;


这些都只是表现,具体的原理可以看下这篇文章:深入理解JavaScript系列(19):求值策略(Evaluation strategy);

回头来看你遇到的问题:

javascriptvar Lan = function(){};
var Attr1 = function(){
    this.name = 'attr1';
};// 假设 内存地址为 0xFE
var Attr2 = function(){
    this.name = 'attr2';
};// 假设 内存地址为 0xFF

Lan.prototype.attr = new Attr1(); // Lan.prototype.attr 指向 内存地址 0xFE

var lan = new Lan();
var obj = lan.attr;//这里 obj 指向 内存地址 0xFE
console.log(obj);//输出Attr1 {name: "attr1"}   => 0xFE

Lan.prototype.attr = new Attr2();// Lan.prototype.attr 指向 内存地址 0xFF
console.log(obj);//输出Attr1 {name: "attr1"}   => 0xFE
console.log(lan.attr);//输出Attr2 {name: "attr2"}   => 0xFF

你遇到的问题 关键在 var obj = lan.attr; 这个赋值引起的;
可以这么理解 obj 在赋值的时候 获得了 lan.attr 的内存地址 0xFE;
后面再修改 Lan.prototype.attr的内存地址为 0xFF,并不会影响到 obj;
所以 console.log(obj);console.log(lan.attr);的结果并不一样;

注: 内存地址只是我自己的理解,并不一定准确;


你下面打印错了,你改变原型之后,打印的还是之前new的那个lan,所以当然还是一样的结果,上代码,我手机端,无法编辑代码格式,你凑合看,主要我下面new了一个新的lan1,然后打印lan1,也就是更改之后的,
var Lan = function(){};
var Attr1 = function(){
this.name = 'attr1';
}
var Attr2 = function(){
this.name = 'attr2';
}

Lan.prototype.attr = new Attr1();

var lan = new Lan();
var obj = lan.attr;
console.log(obj.name)

Lan.prototype.attr = new
Attr2();
var lan1=new Lan;
var obj1=lan.attr;

console.log(obj1.name);//输出Attr2


var foo = {};
foo.a = 'aa';
var bar = foo.a
console.log(bar);    //aa
foo.a = 'bb';
console.log(bar);    //aa

简化下,大概是这样吧


我们可以分解下看看:

...
// 把Attr1的一个instance赋值给Lan.prototype.attr,即Lan.prototype.attr指向了这个Attr1的instance
// 记作attr1Instance
Lan.prototype.attr = new Attr1();

var lan = new Lan();

// 这里obj指向了attr1Instance
var obj = lan.attr;

// 让Lan.prototype.attr指向Attr2的一个instance, 
// 这里并没有改变obj的指向
Lan.prototype.attr = new Attr2();

最后, 如果console.log(lan.attr), 应该得到[Object] {name: 'attr2'}

【热门文章】
【热门文章】