We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
写在前面,本文让读者产生了误会。有这样一些原因:
a.x = a
首先:本文用addr只是一个代称,表达的是该地址对应的那块内存。 关于2.3点就是本次更新的原因
a.x = a = {n : 2}
a.x
a
将题目改写成: var a = {n: 1}; var b = a; a.x = a = a.y = {n: 2}; //改写成这样,那么怎么确定优先级呢?
现在按照我文章的思路来:
addr(a.x) = addr(a) = addr(a.y) = addr({n : 2})
addr(a) = 0x100, addr(a.x) = 0x101, addr(a.y) = 0x102, addr({n : 2}) = 0x888, addr({n : 1}) = 0x999
2.(从右往左)将右边的值赋值给左值,然后将其作为该赋值表达式的值返回:
1. 先执行:addr(a.y) = addr({n : 2}),将{n : 2}的地址值存放在addr(a.y)这个地址值对应的内存!中。 (别用箭头指,容易混淆,简单的当做赋值就好了。本文就是犯得这个错,导致没有说清楚。) 2. 然后将addr(a.y) = addr({n : 2})的右值作为该表达式的返回值N返回,在这里会作为下一个赋值表达式的右值。 3. 接着执行addr(a) = N,同上返回N。 4. 接着执行addr(a.x) = N,返回N。 然后我们执行 console.log(a); // {n : 2} console.log(a.x); // undefined console.log(a.y); // undefined console.log(b.x); // {n : 2} console.log(b.y); // {n : 2}
因为此时a(0x100)这块内存存的是对{n : 2}的引用,它会去0x888这块内存中找,这样肯定找不着x和y,因为他们在0x999内存中。
而b在一开始var b = a的时候,就将a(0x100)这块内存中存的(0x999)拷贝过来。而y和x就在0x999对应的内存下。所以b找的到。
有这样一道面试题
var a = {n: 1}; var b = a; a.x = a = {n: 2}; alert(a.x); // undefined alert(b.x); // [object, Object]
一开始没有太好思路,或者说是没有想明白,经过一番折腾,算是整理清楚了思路,接下来会一一讲明白,希望能对其他人有所帮助。
开始之前,需要清楚赋值表达式是怎么执行的。首先先明白什么是什么是右结合性和什么是赋值表达式:
赋值运算符是右结合性的,如果不知道,就请记住啦! 形如:
A = B = C = D
等价于
A = (B = (C = D))
A = B这就是一个赋值表达式,并且一个赋值表达式存在一个左值和一个右值,这可不是胡编乱造的,咱们说话有理有据: 引用链接(11.13.1 Simple Assignment ( = ) )
A = B
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: Let lref be the result of evaluating LeftHandSideExpression. Let rref be the result of evaluating AssignmentExpression. Let rval be GetValue(rref). Throw a SyntaxError exception if the following conditions are all true: Type(lref) is Reference is true IsStrictReference(lref) is true Type(GetBase(lref)) is Environment Record GetReferencedName(lref) is either "eval" or "arguments" Call PutValue(lref, rval). Return rval.
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
翻译过来:
大体来说 赋值表达式:左边的表达式 = 赋值表达式 具体评判的步骤如下: 将比左边的表达式的值称为'lref' 将右边赋值表达式的值称为'rref' 将'rval' 作为GetValue(rref)'的返回值 如果下列情况为true就会报错 balala~~~~ 调用 PutValue(lref, rval) 返回'rval'
大体来说 赋值表达式:左边的表达式 = 赋值表达式 具体评判的步骤如下:
由上面可以清楚的知道表达式运算的流程:
(等等,这里有疑问,为什么运算两遍右边?第一遍是计算右边表达式的(+ — * /)所得到的值,第二遍是返回这个结果值,也就是每个表达式都有返回值!)
如果还没理解的话,没关系,往下看,我会画图帮助理解。
有了以上两个知识点,下面来分析一下题目。
真正难以理解的是在第三句代码a.x = a = {n: 2} 下面咱们开工吧!
a.x = a = {n: 2}
第一、二句代码执行之后,内存图如下:
第三句代码先进行改写
a.x = a = {n: 2}; //先右结合性 a.x = (a = {n : 2}) //在计算等号左边的值 addr(a.x) = (addr(a) = {n : 2}) //在计算等号右边的值 addr(a.x) = ( addr(a) = value( {n : 2} ) )
如图:
如上图来进行运算 addr(a.x) = ( addr(a) = value( {n : 2} ) )
addr(a.x) = ( addr(a) = value( {n : 2} ) )
(0x8889 <-- (0x0001 <-- (0x9999)))
一开始找到当前表达式左右左边的值,也就是他们地址值。然后依次将右值逐个放到对应的内存!
最后因为a的地址是指向0x9999的,且其不存x这个属性,故返回undefined。而b的地址指向里面存在一个保存{n:2}的地址的x属性,故返回的是对象。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
更新(1/23/2018)
写在前面,本文让读者产生了误会。有这样一些原因:
a.x = a
未解释清楚。首先:本文用addr只是一个代称,表达的是该地址对应的那块内存。
关于2.3点就是本次更新的原因
a.x = a
赋值表达式先确定左值(可以这样理解,如果不确定我要去的地方,取到值又有什么用呢?左边的值在执行赋值之前就已经确定了),然后再将右边表达式的返回值给到左值。那么a.x = a = {n : 2}
就是从左往右先确定a.x
再确定a
,然后将返回值从右往左依次赋值给左边。现在按照我文章的思路来:
addr(a.x) = addr(a) = addr(a.y) = addr({n : 2})
2.(从右往左)将右边的值赋值给左值,然后将其作为该赋值表达式的值返回:
不对呀,为什么给a.x和a.y的地址值对应的内存赋值了,但却没有东西,你是不是讲错了?
因为此时a(0x100)这块内存存的是对{n : 2}的引用,它会去0x888这块内存中找,这样肯定找不着x和y,因为他们在0x999内存中。
而b在一开始var b = a的时候,就将a(0x100)这块内存中存的(0x999)拷贝过来。而y和x就在0x999对应的内存下。所以b找的到。
希望本次更新对有困惑朋友有所帮助!(也许是我讲复杂了,希望多多提问。)
有这样一道面试题
一开始没有太好思路,或者说是没有想明白,经过一番折腾,算是整理清楚了思路,接下来会一一讲明白,希望能对其他人有所帮助。
开始之前,需要清楚赋值表达式是怎么执行的。首先先明白什么是什么是右结合性和什么是赋值表达式:
右结合性
赋值运算符是右结合性的,如果不知道,就请记住啦!
形如:
A = B = C = D
等价于
A = (B = (C = D))
赋值表达式
A = B
这就是一个赋值表达式,并且一个赋值表达式存在一个左值和一个右值,这可不是胡编乱造的,咱们说话有理有据:引用链接(11.13.1 Simple Assignment ( = ) )
翻译过来:
由上面可以清楚的知道表达式运算的流程:
(等等,这里有疑问,为什么运算两遍右边?第一遍是计算右边表达式的(+ — * /)所得到的值,第二遍是返回这个结果值,也就是每个表达式都有返回值!)
如果还没理解的话,没关系,往下看,我会画图帮助理解。
有了以上两个知识点,下面来分析一下题目。
真正难以理解的是在第三句代码
a.x = a = {n: 2}
下面咱们开工吧!
第一、二句代码执行之后,内存图如下:
第三句代码先进行改写
如图:
如上图来进行运算
addr(a.x) = ( addr(a) = value( {n : 2} ) )
(0x8889 <-- (0x0001 <-- (0x9999)))
一开始找到当前表达式左右左边的值,也就是他们地址值。然后依次将右值逐个放到对应的内存!
最后因为a的地址是指向0x9999的,且其不存x这个属性,故返回undefined。而b的地址指向里面存在一个保存{n:2}的地址的x属性,故返回的是对象。
The text was updated successfully, but these errors were encountered: