论坛首页 Web前端技术论坛

写了10年Javascript未必全了解的连续赋值运算

浏览 31867 次
该帖已经被评为良好帖
作者 正文
   发表时间:2010-11-08  
学习学习了
0 请登录后投票
   发表时间:2010-11-08  
//感觉这个问题大家说的有点复杂
var a=[1,2,3]
alert(a[2]) //3 因为数组有这个值a[2]所以当然要返回了
a[2]=a=[]   // ?
alert(a[2]) //undefined
            //常规思维
              //如果要给变量赋值哪么首先是确定变量本身的属性,比如要给a[2]赋值
              //首先计算a[2]之前是什么,如果没有定义a是一个数组哪么此时脚本就会直接报错
              //因为 var a=[1,2,3]
            //既然此时确定了a[2]的值是3
            //a[2]=3
              //哪么往下走:从右到左,先执行a=[]此时的a是一个空数组[],也就是改变了
              //原始定义的var a=[1,2,3]值的变量定义值a=[]
            //接着往右赋值a[2]=[],也就是说此时的a[2]不管值是多少,是继承自var a=[1,2,3]
            //而不是a=[]
            //因为a=[]没有a[2]这个元素, 此时a[]既然没有a[2]这个元素哪么    
              //a[2]==undefined相当于:

var a=[]
    a[2]=?  //没有值,当然返回的是undefined

0 请登录后投票
   发表时间:2010-11-09  
我是一名新手下面是我的理解,先看下面一个例子
 		int i = 0;
		i = i++;
		System.out.println("i = " + i);//i = 0;

这段代码分如下步骤执行
(1)i = 0 ,读取变量i的地址,把0的值赋给i;
(2)i = i ++ ,因为=的优先级高于++,所以先执行赋值运算符=,编译器读取右边i的地址
(3)读取左边的i的地址(编译器并不认为右边i的地址等于左边的i的地址)
(4)右边i++
(5)打印左边的i值(因为编译器拿到的是左边的i的值)
可以看出编译器按下面处理
int i = 0;
int j = 0;//
j = i ++ ;
System.out.println("j = " + j);
其实,我认为上面的代码也是一样的
    	var a = {n:1};
    	a.x = a = {n:2};
    	alert(a.x);

a.x = a = {n:2};左边a.x中的a和右边的a代表两个不同的地址,解释器如下处理;
    	var a = {n:1};
    	var b = {n:1};
    	b.x = a = {n :2};
    	alert(b.n);
    	alert(a.n);
    	alert(a.x);  

    	var a = {n:1};
    	a.x = a = {n:2};//a.x中的a指向的是 {n:1},
    	alert(a.n);//2 ,证明解释器拿到的是 a = {n:2};
    	alert(a.x);//	

0 请登录后投票
   发表时间:2010-12-29  
昨天遇到一位大神告知
var a=b=1;
运行时会报错,怎么都有点想不明白,试着尝试运行了一下,发现并没有出错提示,有点不甘心,看到
var a = {n:1}; 
a.x = a = {n:2}; 
alert(a.x); // --> undefined 
感觉原理有点类似, 遂改写了一下
var a; 
a.x = a = {n:2}; 
alert(a.x);
居然真的报错了!看了上面各位的解释,这里在做一点小小补充,以便新手能够理解:
1.赋值运行算的顺序是从右到左的;
2.JS垃圾回收不会在语句执行时进行.

a.x = a = {n:2};  这条语句执行过程猜得没错的话应该是
1.查找a并得到a的引用
2.查找a.x发现未定义就重新分配内存并得他的引用
3.再次查找a并得到a的引用
4.给{n:2}分配内存并得到他的引用
5.将新a的引用指向{n:2}的引用
//注意:这里本来应该回收旧a及旧a的x,但因为执行完这条语句后才能GC,所以尚未销毁a,即第2步中的旧a.x的引用在内存中仍然存在
6.将旧a的x指向新的a的引用
7.垃圾回收旧a及旧a的x

个人见解,难免有误,欢迎指正.
0 请登录后投票
   发表时间:2011-01-17  
a.x = a = {n:2};
1. a={n:2};
2. a.x={n:2};   //此时的a为{n:1},即{n:1}.x={n:2};

所以alert(a.x)为undefined, 因为此时的a已经指向{n:2}, 没有为它的x属性赋值。
0 请登录后投票
   发表时间:2011-02-14  
rainsilence 写道
看了两遍才明白。实际上最后alert(a.x);的a是{n:2},a.x=a的左边的a是{n:1}。
也就是说最后赋值的那个a,没有地方引用,所以alert(a.x);才会是未定义




LZ写了这么多也没明白。看这一句就明白了。。
0 请登录后投票
   发表时间:2011-02-14  
对于lz第5点
 function fun(){  
     var a = b = 5;  
 }  
fun();  
alert(typeof a); // --> undefined  
alert(typeof b); // --> number 



其中
var a=b=5;

只是声明了局部变量a,而b并未声明,对于未声明的变量直接在js中赋值就会当做全局变量。
所有b本来就可以在外部读到。
0 请登录后投票
   发表时间:2011-02-16   最后修改:2011-02-16
看这个代码
var a,b,c,d;
a=b=c=d={a:1};
a.x=a=b.y=b=c.z=c={}
console.log(a,b,c,d)

和结果:

我觉得是这样的,执行这句话的时候,发现有a.x b.y c.z,虚拟机会先把地址准备好,也就是虚拟机要做这件事:
先分别找a.x、a、b.y、b、c.z、c的地址,这时,a.x,b.y,c.z 分别指向旧对象内部的地址,而a,b,c分别为存放对象指针的地址,当赋值时,会将所有这些地址的值都赋值成赋值语句最右面的值。但是由于a.x,b.y,c.z分别指向旧对象的x、y、z域,故这几个值是赋给了就对象,即d,而a、b、c分别赋予了新值,即空对象,所以可以看到如图的结果

纯属推测,也许不是地址,是一个临时的setter也不一定,总之是虚拟机内部实现的。
这帖子里的问题和这个是一样的问题吧。
  • 大小: 17.2 KB
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics