对Js赋值运算的新熟悉

能够在这里看:http://leozdgao.me/renew-js-assignment/

此文的目标是为了诠释以下征象:

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

赋值运算符

依据ECMA范例中的定义赋值运算符的发生式(production)以及运算历程以下:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.

  2. Let rref be the result of evaluating AssignmentExpression.

  3. Let rval be GetValue(rref).

  4. 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”

  5. Call PutValue(lref, rval).

  6. Return rval.

实在第一次看这个部份我也照样没法明白最先列出的谁人代码中效果究竟是为何,看了其他博客实在也没有讲清晰,在StackOverflow上相干题目中有诠释到说是由于起首剖析左侧表达式时肯定了援用的指向,而只看11.13.1的话,只要一句“猎取LeftHandSideExpression的盘算效果”,所以我觉得要真正明白,只看11.13.1是不可,还须要了解下11.2.1关于Property Accessors的内容,从而晓得这个“盘算效果是怎样获得的”:

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

  1. Let baseReference be the result of evaluating MemberExpression.

  2. Let baseValue be GetValue(baseReference).

  3. Let propertyNameReference be the result of evaluating Expression.

  4. Let propertyNameValue be GetValue(propertyNameReference).

  5. Call CheckObjectCoercible(baseValue).

  6. Let propertyNameString be ToString(propertyNameValue).

  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.

  8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

症结点在于它的返回值,用一个栗子来诠释就是说:如果有表达式foo.x,则它的返回值是一个指向foo对象x属性的援用

那末在晓得了这一点后,最先诠释上面的征象:

起首是两个变量的声明和初始化,var foo = { n: 1 }; var bar = foo;,这个很好明白,就是foo和bar同时指向了一个雷同的对象{ n: 1 }

接下来,关于表达式foo.x = foo = { n: 2 };,我们都晓得它实际上等于是foo.x = (foo = { n: 2 })。我们最先应用上ECMA范例上的步骤,虽然赋值运算符具有右连系性,但是它起首做的是获得表达式foo.x的值,依据我们对Property Accessors的诠释它返回一个指向对象{ n: 1}的x成员的援用,须要注重的是,这个时刻foo并没有转变援用的指向。

继承,最先盘算右侧的效果,就是让foo指向别的的一个对象{n: 2},返回值就是其右侧运算式(operand)的效果,即对象{n: 2}这个轻易明白。

那末如今应当清晰了,赋值语句中foo.x的效果是指向对象一成员x的援用,而下面的console.log(foo.x)中的foo指向的是对象二,所以这里foo.x返回undefined就天经地义了。

所以试着输出对象一,即bar(由于它从始至终指向的是对象一):

{ n: 1, x: { n: 2 } }

如果有其他意见,接收各种形式的补充和斧正。

    原文作者:leozdgao
    原文地址: https://segmentfault.com/a/1190000002965140
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞