(转)深入理解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)的内容. 上一篇我们讲到在全局环境下的代码段中,执行上下文环境中有如何数据: ...
随机推荐
- Three.js开发指南---使用three.js里的各种光源(第三章)
本章的主要内容 1 three.js有哪些可用的光源 2 什么时候用什么光源. 3 如何调整配置各种光源 4 如何创建镜头炫光 一 光源 光源大概有7种, 其中基础光源有4种 环境光(AmbientL ...
- Add Digits, Maximum Depth of BinaryTree, Search for a Range, Single Number,Find the Difference
最近做的题记录下. 258. Add Digits Given a non-negative integer num, repeatedly add all its digits until the ...
- MySQL基础原创笔记
对表的增删改操作: 创建表: create table student ( id int primary key auto_increment, name ...
- json&pickle&xml
json .dumps() 变成 json 的字符串 import json dic={"name":"alex"} data=json.dumps(di ...
- 事实证明,abstract类除了不能用new实例化和类没什么区别
abstract类是抽象类,不能够实例化,大家都知道,abstract类往往和接口interface一块儿使用,针对接口中一些公共的方法进行实现,然后实体类去继承抽象类和接口.虽然abstract类不 ...
- [Linux编程] module_param()函数学习笔记
在读TCP cubic源码中,遇到了module_param(),网上查到的资料如下: 在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递 ...
- cocos2d-x3.2创建新项目失败的一种可能性(cygwin自带的python2.6被抢先执行)
之前一直使用cocos2d-x2.2写游戏,写了几个游戏后,想尝试下3.x版本的新功能,就下载了cocos2d-x3.2版本. 参照官方文档的说法,cocos2d-x3.x版本需要python2.7环 ...
- 转(Response.WriteFile 无法下载大文件解决方法)
以前用Response.WriteFile(filename),但当遇到大文件时无法完整下载. 该方法最大的问题,它不是直接将数据抛到客户端,而是在服务器端(IIS)上缓存.当下载文件比较大时,服务器 ...
- Installing Intellij IDEA sublime-text-2 on Ubuntu
he installation on Linux is traditionally more complicated. I wonder why people complain about the l ...
- Mysql使用workbench迁移数据
原文:http://jingyan.baidu.com/article/925f8cb8f3ec25c0dce05644.html 打开Mysql WorkBench,连接到数据库: 首先选中:Man ...