[英]Why does the assignment operator return a value and not a reference?
I saw the example below explained on this site and thought both answers would be 20 and not the 10 that is returned. 我在这个网站上看到了下面的例子,并且认为两个答案都是20而不是返回的10。 He wrote that both the comma and assignment returns a value, not a reference. 他写道,逗号和赋值都返回一个值,而不是引用。 I don't quite understand what that means. 我不太明白这意味着什么。
I understand it in relation to passing variables into functions or methods ie primitive types are passed in by value and objects by reference but I'm not sure how it applies in this case. 我理解它与将变量传递给函数或方法有关,即原始类型是通过值传递的,而对象是通过引用传递的,但我不确定它在这种情况下是如何应用的。
I also understand about context and the value of 'this' (after help from stackoverflow) but I thought in both cases I would still be invoking it as a method, foo.bar() which would mean foo is the context but it seems both result in a function call bar(). 我也理解上下文和'this'的值(在stackoverflow的帮助之后),但我认为在这两种情况下我仍然会调用它作为方法,foo.bar()这意味着foo是上下文但它似乎都导致函数调用bar()。
Why is that and what does it all mean? 为什么会这样,这一切意味着什么?
var x = 10;
var foo = {
x: 20,
bar: function () {return this.x;}
};
(foo.bar = foo.bar)();//returns 10
(foo.bar, foo.bar)();//returns 10
It doesn't have to do with values vs. references, it has to do with this
values (as you suspected). 它与值与引用无关,它与this
值有关(如您所怀疑的那样)。 In JavaScript, this
is set entirely by how a function is called, not where it's defined. 在JavaScript中, this
完全取决于函数的调用方式,而不是函数的定义。 You set the this
value in one of three ways: 您可以通过this
三种方式之一设置this
值:
obj.foo()
) or bracketed notation ( obj["foo"]()
). 使用属性访问符号(通过虚线表示法( obj.foo()
)或括号表示法( obj["foo"]()
)通过对象属性调用该函数。 with
statement (really just a variant of #1, but worth calling out separately, particularly as it's not obvious from the source code) 使用with
语句通过对象属性调用函数(实际上只是#1的变体,但值得单独调用,特别是因为源代码中不明显) apply
or call
features of the function instance. 使用函数实例的apply
或call
功能。 In your examples above, you're not doing any of those, so you end up calling the function with the default this
value, the global object, and so x
comes from there rather than from your foo
object. 在上面的示例中,您没有执行任何这些操作,因此您最终使用默认的this
值(全局对象)调用该函数,因此x
来自那里而不是来自您的foo
对象。 Here's another way to think about what that code is doing: 这是另一种思考代码正在做什么的方法:
var f = foo.bar; // Not calling it, getting a reference to it
f(); // Calls the function with `this` referencing the global object
If you don't directly use a property to actually make the call (instead retrieving the value of the property and then making the call with that), the this
handling doesn't kick in. 如果你不直接使用一个属性来实际调用(而是检索属性的值然后用它调用),那么this
处理就没有了。
You should understand how the internal Reference Type works. 您应该了解内部参考类型的工作原理。
Note: This is not a language data type, is an internal mechanism to handle references. 注意:这不是语言数据类型,是处理引用的内部机制。
A reference is composed of two elements, the base object and a property name . 引用由两个元素组成,即基础对象和属性名称 。
In your example, the foo.bar
reference looks like this. 在您的示例中, foo.bar
引用如下所示。
// pseudo-code
foo.bar = {
baseObject: foo,
propertyName: 'bar'
}
Both, the comma operator and a simple assignment , rely on getting the value of the property name, that causes the base object to be lost, since a single value is returned (this is made through the internal GetValue
operation). 逗号运算符和简单赋值都依赖于获取属性名称的值,这会导致基础对象丢失,因为返回单个值(这是通过内部GetValue
操作完成的)。
This is how the internal GetValue
operation works: 这是内部GetValue
操作的工作方式:
// pseudo-code
GetValue(V) :
if (Type(V) != Reference) return V;
baseObject = GetBase(V); // in your example foo
if (baseObject === null) throw ReferenceError;
return baseObject.[[Get]](GetPropertyName(V));
// equivalent to baseObject[v.PropertyName];
As you see, a value is returned, so the original reference is lost. 如您所见,返回一个值 ,因此原始引用将丢失。
Edit: The key to understand why (foo.bar = foo.bar)();
编辑:理解原因的关键(foo.bar = foo.bar)();
is not equivalent to foo.bar();
不等于foo.bar();
relies in the Simple Assignment Operator, let's see the algorithm: 依赖于简单赋值运算符,让我们看看算法:
11.13.1 Simple Assignment (`=`) The production `AssignmentExpression` : `LeftHandSideExpression` = `AssignmentExpression` is evaluated as follows: 1. Evaluate LeftHandSideExpression. 2. Evaluate AssignmentExpression. 3.Call GetValue(Result(2)). 4.Call PutValue(Result(1), Result(3)). 5.Return Result(3).
Basically when you make (foo.bar = foo.bar)
the actual assignment ( Step 4. ) has no effect because PutValue
will only get the value of the reference and will place it back, with the same base object. 基本上当你创建(foo.bar = foo.bar)
,实际的赋值( 步骤4 )没有任何效果,因为PutValue
只会获取引用的值并将它放回到相同的基础对象。
The key is that the assignment operator returns ( Step 5 ) the value obtained in the Step 3 and as I said before in the GetValue
pseudo-code, this internal method returns a value which doesn't really have a base object . 关键是,赋值运算符返回( 步骤5)在步骤3中得到的值和前面说过在GetValue
伪码,此内部方法返回并没有真正有一个基本对象的值 。
You're misunderstanding it. 你误会了。
Both examples are returning the window
's x
property, since they aren't being directly invoked on foo
. 两个示例都返回window
的x
属性,因为它们不是在foo
上直接调用的。
The value of the this
keyword inside a function depends on the context in which the function was called. 函数内的this
关键字的值取决于调用函数的上下文。
In an ordinary function call (eg, myFunc()
), this
will be the global object, which is usually window
. 在普通的函数调用(例如, myFunc()
)中, this
将是全局对象,通常是window
。
In an object method call (eg, foo.bar()
), this
will be the object on which the function was invoked. 在对象方法调用(例如, foo.bar()
)中, this
将是调用该函数的对象。 (in this case, foo
) (在这种情况下, foo
)
You can set the context explicitly by calling myFunc.call(context, arg1, arg2)
or myFunc.apply(context, argArray)
. 您可以通过调用myFunc.call(context, arg1, arg2)
或myFunc.apply(context, argArray)
显式设置上下文。
Both of your examples are normal invocations of an expression that evaluates to foo.bar
. 这两个示例都是对表达式进行常规调用,该表达式的计算结果为foo.bar
。
Therefore, this
is the window
. 因此, this
是window
。
They are equivalent to 他们相当于
var func = (some expression);
func();
It may help to think of the dot operator as behaving similarly to a with
statement. 将点运算符视为with
语句类似的行为可能会有所帮助。 When you run foo.bar()
, the result is much the same as if you ran: 运行foo.bar()
,结果与运行时的结果大致相同:
with (foo) {
bar(); // returns 20
}
This will run your bar
function with foo
overlaid on top of the global object, allowing it to find the x
in foo
and thus return 20. 这将运行你的bar
函数, foo
覆盖在全局对象的顶部,允许它在foo
找到x
,从而返回20。
If you don't call bar
immediately, though, as in (foo.bar = foo.bar)
, you instead get: 但是,如果你不立即调用bar
,就像在(foo.bar = foo.bar)
,你得到:
with (foo) {
bar; // returns "bar" itself
}
The result is then passed out of the parentheses, producing an intermediate statement like <reference to bar>()
, which has no dot operator, so no with
statement, so no access to foo
, just to the global value of x
. 结果然后从括号中传出,产生一个中间语句,如<reference to bar>()
,它没有点运算符,所以没有with
语句,所以不能访问foo
,只访问x
的全局值。
(The dot operator doesn't actually convert to a with
statement, of course, but the behavior is similar.) (当然,点运算符实际上并不转换为with
语句,但行为类似。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.