jq的源码中有很多连续赋值,类似这样的:
var a = {n:1};
var b = a; // 持有a,以回查
a.x = a = {n:2};
alert(a.x);// --> undefined
alert(b.x);// --> [object Object]
网上有很多解释了,这里我做一下记录而已,化繁为简,比较容易理解的过程是这样的:
给{n:1},{n:2}分别起名个实际持有这两个内存地址的虚拟对象名字,比如:obj1 -》{n:1},obj2-》{n:2}
1)var a = {n:1}; //定义了一个指针a指向内存中的{n:1},即a = obj1->{n:1}
2)var b = a;//定义了b也指向了内存中的{n:1},即b = obj1->{n:1}
3)a.x = {n:2};//本质是obj1.x = {n:2},即改变的是a和b所指向的对象
4)a = {n:2};//a的指针指向了obj2,是一个新的对象
现在的结果是:
a:a = obj2 = {n:2};
b:b = obj1 = {
n:1,
x:{n:2}
}
好了,下面说说实际过程,来自于网络(http://snandy.iteye.com/blog/785445?page=2#comments)评论中写的很清楚了:
简单几点摘抄:
1、求值顺序:从左到右
2、运算符的结合性:右结合,但也是从左到右求值
主要解读 a.x = a = {n:2}; 这句的执行顺序
按照上面两条的规则来看:
1)求值从左到右,那就是先给a.x赋值即a.x = expression
2)解读一下此时的a.x指向谁,此时a指向obj1-》{n:1},即给obj1.x赋值变成了obj1.x = expression
3)左边解析完了,进入“=”的右边,是一个表达式(a={n:2}),这里为啥不是一个光秃秃的a呢,即为啥不是这样的顺序a.x = a,主要根据第二条,右结合性,
会把a = {n:2}看成一个整体解析(这时候a的指针指向了obj2),返回的是{n:2}
4)赋值,obj1.x = obj2 = {n:2},第3步在解析过程中已经把a的指针指向obj2了,因此a.x(obj2.x)根本没有这个属性,obj1才有
比较难理解的是第三步,明白几点:首先不是先计算右边的值(即不是先计算a = {n:2}),而是先解析左边的规则(指针)a.x,解析成obj1.x之后,才开始到右边,
这时候根据右结合性,把(a={n:2})看成一个整体,然后复制计算。我们的别扭在于一个表达中的a居然指向了不同的对象,就像评论中解释的一样a出现了多次之后,可以看成递归