expression - javascript 中 this 的问题,表达式何时进行求值?
ringa_lee
ringa_lee 2017-04-10 14:53:48
[JavaScript讨论组]
javascriptvar foo={   x:3,
            exe:function(){  
                console.log(this);
                return this.x;
            }
        }

为什么

javascriptvar a = foo.exe;
a();//undefined         NO.1

(foo.exe=foo.exe)()//undefined    NO.2

javascript(foo.exe)() //3       NO.3
foo.exe()   //3       NO.4

特别是 NO.3 这种情况,小括号起到了什么作用?为什么 this 仍然指向这个对象?而 NO.2 和 NO.1 则指向了 window?

ringa_lee
ringa_lee

ringa_lee

全部回复(2)
怪我咯

簡而言之,如果調用函數的表達式的結果(未經求值)是屬性引用,則 this 是屬性引用所在的對象,如果之前已經求值過了,則不再是屬性引用從而導致 this 成爲全局對象。

小括號運算符並不會導致表達式被求值,所以只影響解析時的優先級,不影響結果。


關於表達式,什麼是表達式?先看什麼是語句。

Statement :
    Block
    VariableStatement
    EmptyStatement
    ExpressionStatement
    IfStatement
    IterationStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    WithStatement
    LabelledStatement
    SwitchStatement
    ThrowStatement
    TryStatement
    DebuggerStatement

注意其中 ExpressionStatement。

ExpressionStatement :
    [lookahead ∉ {{, function}] Expression ;

也就是說,除了上面列出的情況,以及 {, function 開頭的情況,都是表達式構成語句。

foo 是表達式,foo.bar 是表達式,foo.bar() 也是表達式。

foo.bar(); 是一個語句,完全由表達式構成的語句。


foo.bar()

是一種語法糖。

函數調用其實就是:

CallExpression :
    MemberExpression Arguments

MemberExpression :
    PrimaryExpression
    FunctionExpression
    MemberExpression [ Expression ]
    MemberExpression . IdentifierName
    new MemberExpression Arguments

http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.3 當中說 Function Calls:

Let ref be the result of evaluating MemberExpression.
Let func be GetValue(ref).
...
If IsPropertyReference(ref) is true, then
    Let thisValue be GetBase(ref).

也就是說,如果 MemberExpression 是一個 PropertyReference,就將 this 設置成訪問的對象。

所以,

var a = foo.bar;
a();

以及

(foo.bar = foo.bar)();

當中的 MemberExpression 都不是 PropertyReference,因此 this 默認是全局對象(直接訪問 a 是一個值,通過包含 = 的表達式(屬於 AssignmentExpression)返回的也是值)。

因爲賦值操作對表達式進行了 GetValue,所以不再是一個 PropertyReference。

小括號如果是表達式的一部分,那麼相當於:

PrimaryExpression :
    this
    Identifier
    Literal
    ArrayLiteral
    ObjectLiteral
    ( Expression )

當中的 ( Expression )

直接返回其中表達式(相當於小括號被無視,只起到改變優先級的功能)。

而取最後結果在函數調用時纔進行,所以仍舊可以屬於 PropertyReference

The Grouping Operator

The production PrimaryExpression : ( Expression ) is evaluated as
follows:

Return the result of evaluating Expression. This may be of type
Reference. NOTE This algorithm does not apply GetValue to the result
of evaluating Expression. The principal motivation for this is so that
operators such as delete and typeof may be applied to parenthesised
expressions.

由於 Grouping Operator 並不會進行 GetValue 操作,

所以:

(foo.bar)();

等價於:

foo.bar();
大家讲道理

前两种情况是一样的,相当于返回了这个函数。括号只是用来表示优先级的,而第二个和第三个的区别是第二个是一个表达式,有返回的。拆开来就是

var a = (foo.exe = foo.exe);
a();

函数的this只和运行时的上下文有关,和声明定义时的上下文无关。此时a 变量的上下文就是 window 所以 this.x 自然是 undefined

第三种和第四种的情况是一样的,那个括号加上和没加都一样,具体就不多表了,不懂的话再提出来吧。

最后,SF 上关于 this 的问题非常多,你提出的这个也有相关的问题,可以搜索学习一下。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号