资讯专栏INFORMATION COLUMN

对Js赋值运算的新认识

sean / 300人阅读

摘要:我们开始应用上规范上的步骤,虽然赋值运算符具有右结合性,然而它首先做的是得到表达式的值,根据我们对的解释它返回一个指向对象的成员的引用,需要注意的是,这个时候并没有改变引用的指向。

可以在这里看:http://leozdgao.me/renew-js-assignment/

此文的目的是为了解释如下现象:

var foo = { n: 1 };
var bar = foo;
foo.x = foo = { n: 2 };
console.log(foo.x); // undefined
赋值运算符

根据ECMA规范中的定义赋值运算符的产生式(production)以及运算过程如下:

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

Let lref be the result of evaluating LeftHandSideExpression.

Let rref be the result of evaluating AssignmentExpression.

Let rval be GetValue(rref).

Throw a SyntaxError exception if the following conditions are all true:

Type(lref) is Reference is true

IsStrictReference(lref) is true

Type(GetBase(lref)) is Environment Record

GetReferencedName(lref) is either "eval" or "arguments"

Call PutValue(lref, rval).

Return rval.

其实第一次看这个部分我也还是无法理解开始列出的那个代码中结果到底是为什么,看了其他博客其实也没有讲清楚,在StackOverflow上相关问题中有解释到说是因为首先解析左边表达式时确定了引用的指向,而只看11.13.1的话,只有一句“获取LeftHandSideExpression的计算结果”,所以我觉得要真正理解,只看11.13.1是不行,还需要了解下11.2.1关于Property Accessors的内容,从而知道这个“计算结果是如何得到的”:

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

Let baseReference be the result of evaluating MemberExpression.

Let baseValue be GetValue(baseReference).

Let propertyNameReference be the result of evaluating Expression.

Let propertyNameValue be GetValue(propertyNameReference).

Call CheckObjectCoercible(baseValue).

Let propertyNameString be ToString(propertyNameValue).

If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.

Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

关键点在于它的返回值,用一个栗子来解释就是说:如果有表达式foo.x,则它的返回值是一个指向foo对象x属性的引用

那么在知道了这一点后,开始解释上面的现象:

首先是两个变量的声明和初始化,var foo = { n: 1 }; var bar = foo;,这个很好理解,就是foo和bar同时指向了一个相同的对象{ n: 1 }

接下来,对于表达式foo.x = foo = { n: 2 };,我们都知道它实际上等于是foo.x = (foo = { n: 2 })。我们开始应用上ECMA规范上的步骤,虽然赋值运算符具有右结合性,然而它首先做的是得到表达式foo.x的值,根据我们对Property Accessors的解释它返回一个指向对象{ n: 1}的x成员的引用,需要注意的是,这个时候foo并没有改变引用的指向。

继续,开始计算右边的结果,就是让foo指向另外的一个对象{n: 2},返回值就是其右边运算式(operand)的结果,即对象{n: 2}这个容易理解。

那么现在应该清楚了,赋值语句中foo.x的结果是指向对象一成员x的引用,而下面的console.log(foo.x)中的foo指向的是对象二,所以这里foo.x返回undefined就理所当然了。

所以试着输出对象一,即bar(因为它从始至终指向的是对象一):

{ n: 1, x: { n: 2 } }

如果有其他看法,接受各种形式的补充和指正。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85783.html

相关文章

  • C++类和象(万字总结)(建议收藏!!!)

    摘要:当你用该日期类创建一个对象时,编译器会自动调用该构造函数对新创建的变量进行初始化。注意构造函数的主要任务并不是开空间创建对象,而是初始化对象。编译器对内置类型使用默认构造函数时,对其成员赋的是随机值。 ...

    masturbator 评论0 收藏0
  • 面试官问:JS的this指向

    摘要:之前写过一篇文章面试官问能否模拟实现的和方法就是利用对象上的函数指向这个对象,来模拟实现和的。虽然实际使用时不会显示返回,但面试官会问到。非严格模式下,和,指向全局对象 前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实。读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论区评论不同之处),...

    warnerwu 评论0 收藏0
  • SICP Python 描述 1.3 定义新的函数

    摘要:到目前为止,我们的环境只包含全局帧。要注意函数名称是重复的,一个在帧中,另一个是函数的一部分。运算符字表达式是全局帧中发现的名称,绑定到了内建的加法函数上。严格来说,这并不是问题所在不同局部帧中的的绑定是不相关的。 1.3 定义新的函数 来源:1.3 Defining New Functions 译者:飞龙 协议:CC BY-NC-SA 4.0 我们已经在 Python 中认识...

    SegmentFault 评论0 收藏0
  • 严格模式的简单认识

    摘要:不支持严格模式的浏览器与严格模式的浏览器行为也不一样,所以不要在未经严格模式特性测试情况下使用严格模式。在严格模式下,使用上述标识符作为变量名会导致语法错误。严格模式下,命名参数与对象是完全独立的。在严格模式下,函数的值始终是指定的值。 严格模式 概述 严格模式是什么 严格模式是JavaScript中的一种限制性更强的变种模式。严格模式不是一个子集:它的语义上与正常代码有着明显的差异。...

    learning 评论0 收藏0
  • 十八问,认识Python序列,解决疑难杂症!

    摘要:序列是中的重要数据结构,序列包括字符串,列表,元组。序列支持运算符吗运算符是否支持算数运算符支持加法与乘法操作,返回新的序列比较运算符支持,返回与逻辑运算符支持注意必须是同种类型数据结构操作才有意义。 序列是Python中的重要数据结构,序列包括字符串,列表,元组。大部分朋友学习Python的时候都会找本书或者资料从头看到尾,这次我们换一个思路,问答式的方式,可能让我们精力更集中,下面...

    cjie 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<