简体   繁体   English

为什么赋值运算符返回值而不是引用?

[英]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值:

  1. Call the function via an object property using property accessor notation, either dotted notation ( obj.foo() ) or bracketed notation ( obj["foo"]() ). 使用属性访问符号(通过虚线表示法( obj.foo() )或括号表示法( obj["foo"]() )通过对象属性调用该函数。
  2. Call the function via an object property using a 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的变体,但值得单独调用,特别是因为源代码中不明显)
  3. Use the apply or call features of the function instance. 使用函数实例的applycall功能。

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 . 两个示例都返回windowx属性,因为它们不是在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 . 因此, thiswindow

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.

相关问题 为什么引用&#39;this&#39;会返回值,它应该是未定义的? - Why does reference to 'this' return the value, it should be undefined? Javascript:为什么对象赋值中的“=”运算符会创建对已存在对象的引用? - Javascript: Why does the '=' operator in object assignment creates a reference to the already existing object? 为什么在三元运算符中使用“0”会返回第一个值? - Why does using “0” with the ternary operator return the first value? 为什么&#39;+ =&#39;运算符返回未定义? - Why does the '+=' operator return undefined? 为什么赋值运算符返回非布尔值 - why assignment operators return non boolean value Angular Service-返回私有值与通过引用私有值进行分配 - Angular Service - return private value versus assignment by reference to private value JavaScript-这些值分配(使用| =作为运算符)是什么意思? - JavaScript - What does these value-assignment (using |= as an operator) mean? 为什么AND(&amp;&amp;)运算符返回数组而不是布尔值? - Why does the AND (&&) operator return an array instead of a boolean? 为什么模运算符返回true? - Why does the modulo operator return true? 为什么in运算符对于未定义的属性返回true? - Why does the in operator return true for a property that is undefined?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM