允许 `p.foo = o.foo` 到 return 函数 `foo` 的引用的 javascript mechanism/rules 是什么?
what is the javascript mechanism/rules that allow `p.foo = o.foo` to return a reference to the function `foo`?
我目前正在学习javascript "you dont know js" 系列丛书。
在 "this & object prototype" 部分,在讨论 "indirect references to functions" 时,作者指出
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
The result value of the assignment expression p.foo = o.foo is a
reference to just the underlying function object. As such, the
effective call-site is just foo(), not p.foo() or o.foo() as you might
expect. Per the rules above, the default binding rule applies.
显然,(p.foo = o.foo)
return 是对函数 foo
的引用。但是允许 (p.foo = o.foo)
return 引用函数 foo
的 mechanism/rules 是什么?换句话说,为什么要简单地赋值 return 对 foo
函数的引用?
当我想理解这样的东西时,我发现逐步分解它很有帮助。
o.foo
查看 o
对象并找到一个名为 foo
的 属性。它 returns 是 属性 的引用,无论它是什么。在这种情况下,o.foo
属性 是对函数 foo
. 的引用
p.foo = o.foo
从上面获取结果(对函数 foo
的引用),在 p
对象中创建一个 属性 也命名为 foo
.所以现在 p.foo
也是对 foo
函数的引用,与 o.foo
. 完全一样
- 该表达式包含在括号中,所以现在您拥有
=
符号或 p.foo
左侧的任何内容,这(作为提醒)仍然是对foo
函数。
- 现在我们在最后找到
()
。这会调用我们此时手头上的任何函数。那就是 foo
函数。请特别注意,我们 不是 调用 p.foo()
。那将是对 p.foo
引用的函数的方法调用,因此在该函数内部,this
将设置为 p
。但我们没有这样做。我们只是调用 ( p.foo = o.foo )
返回的任何函数。和以前一样,这是相同的 foo
函数,但我们现在已经失去了它可能与 o
对象或 p
对象的任何联系。
- 因此,当我们最后进行该调用时,我们只是调用了
foo
函数,而没有将 this
设置为任何特定对象。因此,当我们进行调用时,this
设置为 undefined
。
- 但是我们不是 运行 处于
strict
模式,所以 JavaScript "helpfully" 不想给我们一个未定义的 this
,所以它将 this
设置为浏览器中的 window
对象或 Node 中的 global
对象。
- 之前我们做过
var a = 2;
。所以 window
或 global
对象实际上现在有一个名为 a
的 属性,并且 属性 的值是 2
.
- 所以现在当我们执行
console.log(this.a)
时,我们从 window
或 global
对象中获取 a
属性。该值为 2
.
如果所有这些代码都不是 运行 在全局级别,而是在函数内部怎么办?那会发生什么?
function test() {
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2, but now is undefined
}
test();
现在当我们在 foo
中调用 console.log( this.a );
时,this
仍然引用 window
或 global
对象。但是当我们设置 var a = 2;
时,我们不再设置全局 属性。我们只是在创建一个局部变量。 window.a
或 global.a
是 undefined
(除非之前有其他代码设置)。
严格模式避免了一些这种怪异现象。如果我们在代码的顶部放置一个 'use strict';
,它将以严格模式编译。现在当我们在最后调用函数 foo
时(同样不是方法!),this
现在设置为 undefined
而不是window
或 global
。因此,当我们尝试调用 console.log(this.a)
时,代码会失败,因为 this
与 undefined
相同,而 undefined
没有(也不能)有一个 a
属性.
让我们试试看:
'use strict';
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2 in the original, but now throws an exception
底线,至少对于这个特定的例子:总是使用严格模式!是你的朋友。
赋值运算符 =
是 JavaScript 中的一个表达式,它产生 (returns) 赋值。因为它是一个表达式,所以它可以用在任何允许使用表达式的地方,例如括号内。
例如:
let test = (a = b = c = { name: 'test' })
上面的代码首先计算括号中的表达式并将变量 c
、b
和 a
指向测试对象(按此顺序),然后它会将 test
指向此表达式的生成值。执行该行后,a
、b
、c
和 test
将指向同一个对象。
同样,
(p.foo = o.foo)
会产生 o.foo
返回(技术上它会产生任何 o.foo
指向的东西,也就是函数 foo
)。
至于
(p.foo = o.foo)()
通过在括号后添加额外的 ()
,我们告诉引擎我们想要调用表达式 (p.foo = o.foo)
最终生成的任何内容。因此我们最终调用函数 foo
。 Similar patterns is used in IIFEs.
一个有用的重写是将上面的行视为这样做:
let produced = (p.foo = o.foo)
produced()
我目前正在学习javascript "you dont know js" 系列丛书。
在 "this & object prototype" 部分,在讨论 "indirect references to functions" 时,作者指出
function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2
The result value of the assignment expression p.foo = o.foo is a reference to just the underlying function object. As such, the effective call-site is just foo(), not p.foo() or o.foo() as you might expect. Per the rules above, the default binding rule applies.
显然,(p.foo = o.foo)
return 是对函数 foo
的引用。但是允许 (p.foo = o.foo)
return 引用函数 foo
的 mechanism/rules 是什么?换句话说,为什么要简单地赋值 return 对 foo
函数的引用?
当我想理解这样的东西时,我发现逐步分解它很有帮助。
o.foo
查看o
对象并找到一个名为foo
的 属性。它 returns 是 属性 的引用,无论它是什么。在这种情况下,o.foo
属性 是对函数foo
. 的引用
p.foo = o.foo
从上面获取结果(对函数foo
的引用),在p
对象中创建一个 属性 也命名为foo
.所以现在p.foo
也是对foo
函数的引用,与o.foo
. 完全一样
- 该表达式包含在括号中,所以现在您拥有
=
符号或p.foo
左侧的任何内容,这(作为提醒)仍然是对foo
函数。 - 现在我们在最后找到
()
。这会调用我们此时手头上的任何函数。那就是foo
函数。请特别注意,我们 不是 调用p.foo()
。那将是对p.foo
引用的函数的方法调用,因此在该函数内部,this
将设置为p
。但我们没有这样做。我们只是调用( p.foo = o.foo )
返回的任何函数。和以前一样,这是相同的foo
函数,但我们现在已经失去了它可能与o
对象或p
对象的任何联系。 - 因此,当我们最后进行该调用时,我们只是调用了
foo
函数,而没有将this
设置为任何特定对象。因此,当我们进行调用时,this
设置为undefined
。 - 但是我们不是 运行 处于
strict
模式,所以 JavaScript "helpfully" 不想给我们一个未定义的this
,所以它将this
设置为浏览器中的window
对象或 Node 中的global
对象。 - 之前我们做过
var a = 2;
。所以window
或global
对象实际上现在有一个名为a
的 属性,并且 属性 的值是2
. - 所以现在当我们执行
console.log(this.a)
时,我们从window
或global
对象中获取a
属性。该值为2
.
如果所有这些代码都不是 运行 在全局级别,而是在函数内部怎么办?那会发生什么?
function test() {
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2, but now is undefined
}
test();
现在当我们在 foo
中调用 console.log( this.a );
时,this
仍然引用 window
或 global
对象。但是当我们设置 var a = 2;
时,我们不再设置全局 属性。我们只是在创建一个局部变量。 window.a
或 global.a
是 undefined
(除非之前有其他代码设置)。
严格模式避免了一些这种怪异现象。如果我们在代码的顶部放置一个 'use strict';
,它将以严格模式编译。现在当我们在最后调用函数 foo
时(同样不是方法!),this
现在设置为 undefined
而不是window
或 global
。因此,当我们尝试调用 console.log(this.a)
时,代码会失败,因为 this
与 undefined
相同,而 undefined
没有(也不能)有一个 a
属性.
让我们试试看:
'use strict';
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // was 2 in the original, but now throws an exception
底线,至少对于这个特定的例子:总是使用严格模式!是你的朋友。
赋值运算符 =
是 JavaScript 中的一个表达式,它产生 (returns) 赋值。因为它是一个表达式,所以它可以用在任何允许使用表达式的地方,例如括号内。
例如:
let test = (a = b = c = { name: 'test' })
上面的代码首先计算括号中的表达式并将变量 c
、b
和 a
指向测试对象(按此顺序),然后它会将 test
指向此表达式的生成值。执行该行后,a
、b
、c
和 test
将指向同一个对象。
同样,
(p.foo = o.foo)
会产生 o.foo
返回(技术上它会产生任何 o.foo
指向的东西,也就是函数 foo
)。
至于
(p.foo = o.foo)()
通过在括号后添加额外的 ()
,我们告诉引擎我们想要调用表达式 (p.foo = o.foo)
最终生成的任何内容。因此我们最终调用函数 foo
。 Similar patterns is used in IIFEs.
一个有用的重写是将上面的行视为这样做:
let produced = (p.foo = o.foo)
produced()