博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)深入理解javascript连续赋值表达式
阅读量:4325 次
发布时间:2019-06-06

本文共 2906 字,大约阅读时间需要 9 分钟。

引入

今天逛园子的时候看到一道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); // undefinedconsole.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文档:

 

转载于:https://www.cnblogs.com/MnCu8261/p/6122434.html

你可能感兴趣的文章
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_9、SpringBoot基础HTTP其他提交方法请求实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_12、SpringBoot2.x文件上传实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_11、SpringBoot2.x目录文件结构讲解...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第三节SpringBoot热部署devtool和配置文件自动注入实战_15、SpringBoot2.x配置文件讲解...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_13、jar包方式运行web项目文件上传和访问...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_17、SpringBootTest单元测试实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第三节SpringBoot热部署devtool和配置文件自动注入实战_14、SpringBoot2.x使用Dev-tool热部署...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_19、SpringBoot个性化启动banner设置debug日志...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第三节SpringBoot热部署devtool和配置文件自动注入实战_16、注解配置文件自动映射到属性和实体类实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_20、SpringBoot2.x配置全局异常实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_18、SpringBoot测试进阶高级篇之MockMvc讲解...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第5节 SpringBoot部署war项目到tomcat9和启动原理讲解_23、SpringBoot2.x启动原理概述...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第4节 Springboot2.0单元测试进阶实战和自定义异常处理_21、SpringBoot2.x配置全局异常返回自定义页面...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_32..SpringBoot2.x持久化数据方式介绍...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_34、SpringBoot整合Mybatis实操和打印SQL语句...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_36、SpringBoot整合mybatis之事务处理实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_38、源码编译安装Redis4.x...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_33、SpringBoot2.x整合Mybatis3.x注解实战...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_35、事务介绍和常见的隔离级别,传播行为...
查看>>
小D课堂 - 零基础入门SpringBoot2.X到实战_第9节 SpringBoot2.x整合Redis实战_40、Redis工具类封装讲解和实战...
查看>>