您应该了解内部引用类型的工作原理。
注意: 这不是一种语言数据类型,而是处理引用的内部机制。
引用由两个元素组成,即基本对象和属性名称。
在您的示例中,foo.bar
引用看起来像这样。
foo.bar = {
baseObject: foo,
propertyName: 'bar'
}
这两个操作符逗号运算符和简单赋值都依赖于获取属性名称的值,导致基本对象丢失,因为只返回一个值(这是通过内部GetValue
操作实现的)。
这就是内部GetValue
操作的工作原理:
GetValue(V) :
if (Type(V) != Reference) return V;
baseObject = GetBase(V);
if (baseObject === null) throw ReferenceError;
return baseObject.[[Get]](GetPropertyName(V));
如您所见,返回了一个值,因此原始引用丢失了。
编辑:理解为什么`(foo.bar = foo.bar)();`不等同于`foo.bar();`的关键在于
简单赋值运算符,让我们看一下算法:
11.13.1 简单赋值(`=`)
产生式`AssignmentExpression`:
`LeftHandSideExpression` = `AssignmentExpression`
评估如下:
1. 评估 `LeftHandSideExpression`。
2. 评估 `AssignmentExpression`。
3. 调用 `GetValue(Result(2))`。
4. 调用 `PutValue(Result(1), Result(3))`。
5. 返回 `Result(3)`。
基本上,当你执行`(foo.bar = foo.bar)`时,实际分配(
步骤4)没有任何效果,因为`PutValue`只会获取引用的值并将其放回,使用相同的基对象。
关键在于赋值运算符返回(
步骤5)步骤3中获取的值,就像我之前在
GetValue
伪代码中所说的那样,这个内部方法返回一个没有真正的
基础对象的
值。
(foo.bar = foo.bar)()
真的是我面试问题清单上的热门问题!^.^ - Ben Blank(foo.bar, foo.bar)()
吗?;-) 我的意思是,如果你想要玄学的... - T.J. Crowder