(转)深入理解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)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: ...
随机推荐
- Memcached 数据缓存系统
Memcached 数据缓存系统 常用命令及使用:http://www.cnblogs.com/wayne173/p/5652034.html Memcached是一个自由开源的,高性能,分布式内存对 ...
- C#实现任意大数的计算和简单逻辑命题的证明——前言
介绍 这是本人毕业设计的项目,一直想将其整理成文,可一不小心4年就过去了(这个时间又可以读个大学了).现在给自己定一个目标,一个月时间里将项目的所有关键点都整理出来.不然真怕一眨眼又一个4年过去了,而 ...
- 使用图灵机器人API实现聊天机器人
使用图灵机器人的API需要先注册,获取key才行,这我就不说了,自己到http://www.tuling123.com/注册一个账号即可. 下面就是一个简单的python调用API实现聊天机器人的简易 ...
- double精度问题
一个Double值由2个Double相加,比如明明是91.2 + 2.4,结果应为93.6,为什么结果是93.6000000000001 为什么会无端地在小数点后面加很多个0,最后还是一个1 ? 计算 ...
- ios启动载入启动图片
版本判断: 1.首先你要知道这个键值对的key:id key = (id)kCFBundleVersionKey; 2.同过本地的NSBundle取得当前的版本号. 3.在沙盒中取得对应的版本号. ...
- C#中属性与字段的用法
//People.cs public class People { //字段 private string _name; //属性 作用:保护字段,对字段的取值和赋值进行限定,限制非法字段的摄入 pu ...
- jsoncpp初使用
一 前言 由于最近一个c++项目需要使用json这种数据格式来传输数据, so上网去寻找合适的类库,毕竟对于这种不是很新的技术, 自己造轮子有点得不偿失. 从百度上翻了翻, 基本上就boost跟jso ...
- LeetCode 350. Intersection of Two Arrays II
Given two arrays, write a function to compute their intersection. Example:Given nums1 = [1, 2, 2, 1] ...
- Hive On Spark hiveserver2方式使用
启动hiveserver2: hiveserver2 --hiveconf hive.execution.engine=spark spark.master=yarn 使用beeline连接hives ...
- 细说IIS异常日志 — 你必须知道的功能
最近在跟QAD用Webservice搞接口做数据维护,搞的哥那个叫头大,遇到很多问题,系统的log4net根本就无法记录.话说QAD调我某一个接口,可能包含几百个字段,而且QAD是个产品,所以我这边提 ...