理解javascript中的连续赋值

以前在扒源码时常常看到相似的连续赋值操做:javascript

 var a = b = 1; 

在某度搜了众多前辈的博客,总算对这骚操做有点眉目。java

Case analysis

首先,javascript中连续赋值最典型案例是:spa

var a = {n: 1}; 
var b = a;
a.x = a = {n: 2}; 
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 

 

Analysis in short

var a = {n: 1}; //建立对象{n: 1},a指向对象{n: 1}
var b = a; //将 a中的地址传给b,即 b也指向对象{n: 1}
a.x = a = {n: 2}; 
/*
1)建立对象{n: 1}中的"x"属性
2)将a指向新对象{n: 2}
3) 将对象{n: 1}中的"x"指向新对象{n: 2}
*/
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 

 若是看懂了,下面能够直接忽略2333指针

 

 Analysis in long

我概括了一下,要看懂这个问题要理解三个点:code

  • 此处的a,b是引用类型对象

  • 在javascript中字段访问操做符"."的优先级高于赋值操做符"="blog

  • 出现多个赋值操做符"="时,运算顺序为从右向左ip

 

1. 此处的a,b是引用类型get

引用类型是区别于基本类型的。javasript中的基本类型总共有5种,Undefined、Null、String、Number、Boolean。引用类型有Object,Array,Function,,,blabla~,简单说就是除了5种基本类型,能够说其它都为引用类型。源码

案例中的{n: 1}和{n: 2}都为Object类,即为引用类型。在javascript中当复制保存某个对象时,操做的是对象的引用,但在为对象添加属性时,操做的是实际的对象。即在第一行和第二行命令中a,b其实存储的是对象{n: 1}的引用(地址)。

这有点像C中的指针。以下图,案例第一行命令能够解析为,在堆(heap)中建立了一个对象{n: 1},另外在栈(stack)中建立了变量a,变量a的值为对象{n: 1}的地址,即图中的h[0]。第二行命令意思是再在栈中建立另外一个变量b,变量b的值与变量a的值相等,即为对象{n: 1}的地址。

打个比方,你有一张去餐馆的地图,你把地图复制一份给你的基友,地图是多了一张,但餐馆的实际位置是没有改变的。

2. 运算顺序问题

这一节对应的是第二和第三个点。根据javascript中的运算符优先级 Operator precedence,可知:

  • 在javascript中字段访问操做符"."的优先级高于赋值操做符"="
  • 出现多个赋值操做符"="时,运算顺序为从右向左

所以在运行第三行命令时,分3步执行:

(1)先执行"a.x",此时a储存的仍然是h[0]地址,即指向对象{n: 1}。"a.x"至关于"h[0].x",即在对象{n: 1}中添加了属性"x",变为{n: 1; x: undefined},可是"x"还没赋值;注意,此时对象{n: 1; x: undefined}中的"x"属性是等待赋值的,操做挂起

 (2)再执行"a = {n: 2}",因为{n: 2}是个新对象,则程序在堆中再建立一个对象{n: 2},而且将变量a指向该对象,如图,此时a储存的即为h[1]的地址

(3)最后一步"a.x = a",(1)中被挂起的操做继续执行,对象{n: 1; x: undefined}中的"x"指向对象{n: 2}。运算完成。

3. 结果解释

在运行完上述命令后,变量a指向了新对象{n : 2};变量b 的地址没有发生改变,于是仍指向修改后的对象{n: 1;x: {n : 2}}。

var a = {n: 1}; 
var b = a; 
a.x = a = {n: 2}; 
console.log(a.x); //undefined 
console.log(b.x); //{n: 2} 
相关文章
相关标签/搜索