• (转)深入理解javascript连续赋值表达式


    引入

    今天逛园子的时候看到一道javascript面试题,是关于连续赋值的,正好最近读jQuery源码经常看到这种连续赋值的表达式,所以很感兴趣。

    废话不多说,来看题:

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

    答案:

    console.log(a.x); // undefined
    console.log(b.x) //{n:2}
    View Code

    看到这个答案,我真是百思不得解。。。。 于是网上搜了搜,整理如下:

     以下转自:http://www.iteye.com/topic/785445

     1、引用(Reference)与GetValue & PutValue 

    引用
    A Reference  is a reference to a property of an object. A Reference consists of two components, the base object and the property name.


    “引用”是引用某个对象的一个属性(可能这个对象并没有这个属性),一个引用含“根对象”与“属性名”两个成员。 
    后面以“(根对象,属性名)”来表达一个引用 

    引用
    GetValue (V) 
    1. If Type(V) is not Reference, return V. 
    2. Call GetBase(V). 
    3. If Result(2) is null, throw a ReferenceError exception. 
    4. Call the [[Get]] method of Result(2), passing GetPropertyName(V) for the property name. 
    5. Return Result(4).


    GetValue,即取值操作,返回的是确定的值,而不是引用。(可以理解为变量与变量的值,或指针与指针指向的对象) 

    引用
    PutValue (V, W) 
    1. If Type(V) is not Reference, throw a ReferenceError exception. 
    2. Call GetBase(V). 
    3. If Result(2) is null, go to step 6. 
    4. Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value. 
    5. Return. 
    6. Call the [[Put]] method for the global object, passing GetPropertyName(V) for the property name and W for the 
    value. 
    7. Return.


    PutValue操作只对引用生效,在ECMAScript的描述中,修改对象的属性都是通过Refrence + PutValue进行的 
    (ECMAScript是为了便于表达而引入Reference这个类型,实际上JS语言中并无此类型。The internal Reference type is not a language data type. It is defined by this specification purely for expository 
    purposes.) 

    2、成员表达式(MemberExpression)解释过程 

    引用
    The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows: 
    1. Evaluate MemberExpression. 
      53 
    2. Call GetValue(Result(1)). 
    3. Evaluate Expression. 
    4. Call GetValue(Result(3)). 
    5. Call ToObject(Result(2)). 
    6. Call ToString(Result(4)). 
    7. Return a value of type Reference whose base object is Result(5) and whose property name is Result(6).


    着重看第7步:a value of type Reference 

    3、赋值表达式解析 

    引用
    The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 
    1. Evaluate LeftHandSideExpression. 
    2. Evaluate AssignmentExpression. 
    3. Call GetValue(Result(2)). 
    4. Call PutValue(Result(1), Result(3)). 
    5. Return Result(3).


    这里可以看到左侧得出的是引用,右侧调用GetValue取得的是确定值。 

    那么开始分析a.b = a = {n:2}这个表达式,先假设{n:1}这个对象为OBJ1,{n:2}为OBJ2,全局为GLOBAL。 

    它的解析如下: 
    a.b = Expression1 
    Expression1为另一个赋值表达式: 
    a = {} 

    首先计算a.b = Expression1,按(3)中赋值表达式运行步骤 
    step1先得到引用(OBJ1, "b") 
    step2解析Expression1{ 
       Expression1解析 
       step1得到引用(GLOBAL, "a") 
       step2得到一个对象OBJ2 
       step3取值,仍是OBJ2 
       step4将引用(GLOBAL, "a")赋值为step3结果 
       step5返回OBJ2 

    step3取值,结果同样为OBJ2 
    step4将(OBJ1, "b")赋值为OBJ2 
    step5返回OBJ2 

    最终结果: 
    OBJ1: {n:1, b:OBJ2} 
    OBJ2: {n:2} 
    a : OBJ2 

    PS: 
    我们常说赋值运算是从右至左,是指右边先结合 
    所以a.b = a = {n:2}解析为了a.b = ( a = {n:2}),而不会解析为(a.b = a) = {n:2} 
    如果理解为右边先运算就会有误解了,虽然右边先赋值成功。 

    ----------------------------分割线---------------------------

    附上ECMA262文档:ECMA262

  • 相关阅读:
    导入sql错误
    导入sql错误
    导入sql错误
    导入sql错误
    【翻译】ASP.NET Web API是什么?
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    python中pip安装、升级、升级指定的包
  • 原文地址:https://www.cnblogs.com/MnCu8261/p/6122434.html
Copyright © 2020-2023  润新知