(转)深入理解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}
看到这个答案,我真是百思不得解。。。。 于是网上搜了搜,整理如下:
以下转自:http://www.iteye.com/topic/785445
1、引用(Reference)与GetValue & PutValue
“引用”是引用某个对象的一个属性(可能这个对象并没有这个属性),一个引用含“根对象”与“属性名”两个成员。
后面以“(根对象,属性名)”来表达一个引用
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,即取值操作,返回的是确定的值,而不是引用。(可以理解为变量与变量的值,或指针与指针指向的对象)
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)解释过程
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、赋值表达式解析
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
(转)深入理解javascript连续赋值表达式的更多相关文章
- 深入理解javascript系列(4):立即调用的函数表达式
本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...
- [JS]深入理解JavaScript系列(4):立即调用的函数表达式
转自:汤姆大叔的博客 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行.在详细了解这个之前,我们来谈了解一下"自执行"这个叫法 ...
- 深入理解javascript:揭秘命名函数表达式
这是一篇转自汤姆大叔的文章:http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 前言 网上还没用发现有人对命名函数表达式进去重复深 ...
- <深入理解JavaScript>学习笔记(2)_揭秘命名函数表达式
写在前面的话 注:本文是拜读了 深入理解JavaScript 之后深有感悟,故做次笔记方便之后查看. 感觉这章的内容有点深奥....略难懂啊. 先坐下笔记,加深一下印象吧. 我主要记一下自己感觉有用的 ...
- 深入理解JavaScript系列(2):揭秘命名函数表达式
前言 网上还没用发现有人对命名函数表达式进去重复深入的讨论,正因为如此,网上出现了各种各样的误解,本文将从原理和实践两个方面来探讨JavaScript关于命名函数表达式的优缺点. 简单的说,命名函数表 ...
- 深入理解JavaScript系列(2):揭秘命名函数表达式(转)
前言 网上还没用发现有人对命名函数表达式进去重复深入的讨论,正因为如此,网上出现了各种各样的误解,本文将从原理和实践两个方面来探讨JavaScript关于命名函数表达式的优缺点. 简 单的说,命名函数 ...
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 深入理解javascript原型和闭包(8)——简述【执行上下文】上
什么是“执行上下文”(也叫做“执行上下文环境”)?暂且不下定义,先看一段代码: 第一句报错,a未定义,很正常.第二句.第三句输出都是undefined,说明浏览器在执行console.log(a)时, ...
- 深入理解javascript原型和闭包(9)——简述【执行上下文】下
继续上一篇文章(http://www.cnblogs.com/wangfupeng1988/p/3986420.html)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: ...
随机推荐
- IOS开发之网络编程开源类 Reachability应用
先看Reachability.h发现 #import <Foundation/Foundation.h> #import <SystemConfiguration/SystemCon ...
- NC营改增
收票 select * from jzinv_receive where vinvno='04888118' 1045select * from bd_corp where pk_corp='104 ...
- 用SysTick做的延时计时器
CM3.CM4的内核中都有个24位的SysTick定时器.这两个MCU里边的SysTick大同小异.SysTick的介绍可以参考:(来自CSDN博客的参考)或者(来自百度文库的参考)或者参考<C ...
- nginx长连接设置
http { keepalive_timeout 20; --长连接timeout keepalive_requests 8192; --每个连接最大请求数} events { worker_conn ...
- sklearn学习笔记2
Text classifcation with Naïve Bayes In this section we will try to classify newsgroup messages using ...
- 将dataGridView数据转成DataTable
如已绑定过数据源: DataTable dt = (dataGridView1.DataSource as DataTable) 如未绑定过数据源: public DataTable GetDgvTo ...
- iOS 8潜在的取证问题
Apple于今天正式发布了iOS 8推送升级 大概琢磨了一下: 1. 可以确定,iOS 7中存在的File relay等所谓后门服务已经被修正,目前Oxygen和我们采用这种服务提取的功能将不再适用于 ...
- Oracle分区表!
Oracle 数据库分区表的创建和操作 摘要:在大量业务数据处理的项目中,可以考虑使用分区表来提高应用系统的性能并方便数据管理,本文详细介绍了分区表的使用. 在大型的企业应用或企业级的数据库应用中,要 ...
- 解决oracle 中文入库是乱码的问题
增加两个环境变量: LANG=zh_CN.GBK NLS_LANG = SIMPLIFIED CHINESE_CHINA.ZHS16GBK
- 删除sqlserver代理任务脚本
无法删除SQLSERVER代理任务时可用如下语句试验下 use [msdb] ) set @job_name = N'jobname' --注:job_name为维护计划对应的job name --删 ...