我试图弄清楚使用绑定的范围。我对boundF1
的输出感到困惑.这是怎么回事?
// console.log(x) ReferenceError: x is not defined
// setting this.x - this here is global or window
this.x = 5;
console.log(x) // 5
function f1() {
console.log(x); // 5
console.log(this.x); // 5
}
// Lexically bound this to window
f2 = () => {
console.log(x); // 5
console.log(this.x); // 5
}
f1()
f2()
boundF1 = f1.bind({x:1});
boundF2 = f2.bind({x:1});
boundF1() // 5 1 Why is this not 1, 1. How is x resolved here? Does it check local vars, then global vars. Would it ever use this? What is the scoping rule?
boundF2() // 5 5
原因x
将始终在作用域中查找变量。它与this
(上下文(无关。当你调用.bind
时,你只在函数内部设置this
的值。
当你引用一个独立变量时,如console.log(x)
,解释器将尝试在外部作用域的某个地方找到一个同名的独立变量。在这里,外部作用域最终会到达全局作用域,因此console.log(x)
解析为console.log(window.x)
。
this
的属性不会被添加到函数的变量环境中;要引用this
的属性,你必须显式地这样做,例如:
console.log(this.x);
并不是说你应该使用它,但有with
,它允许您引用对象的属性,就好像它们是独立的变量一样(这听起来像您认为的事情会自动发生(,但强烈建议不要这样做(并且在严格模式下禁止(。
this.x = 5;
function f1() {
with (this) {
console.log(x); // 5
console.log(this.x); // 5
}
}
boundF1 = f1.bind({x:1});
boundF1()
在 f2 中,因为它是一个不可绑定的箭头函数,x
和this.x
都指window.x
。
在 f1 中,x
将首先尝试查找任何局部范围的变量 x,如果不能,则将在全局范围内搜索x
。但是因为它是绑定的,所以this
不再指window
而是你绑定到的对象,所以this.x
是你绑定到的对象的 x 值。
在第一个 print 语句中f1()
的函数中,您打印x
而不是this.x
,因此当您将其与对象{x:1}
Function.prototype.bind()
绑定时,您将this
作为对象传递{x:1}
。 但是在函数中,您是从全局范围读取x
的值,而不是从绑定到的this
上下文中读取的值。
因此,当您执行函数f1
并打印x
时,它首先在本地范围内查找x
,因为它没有找到任何它将在父范围(在这种情况下是全局范围(中查找的内容。
如果在全局范围内没有声明x
,您将获得ReferenceError
:
function f1() {
console.log(this.x); // 1
console.log(x); // ReferenceError as x is not declared in any scope
}
f1.bind({x:1})();
范围规则在 MDN 文档中进行了解释:
作用域也可以在层次结构中分层,以便子作用域具有 访问父范围,反之则不然。