据我所知,“this”应该包含实际用“this”触发函数的对象的属性和函数。 但在下面的例子中它还包含构造函数“foo”的属性,为什么?
function foo(id)
{
var self = this;
this.foo = "foo";
this.element = document.getElementById(id);
this.element.addEventListener("keyup", function(){self.bar();}, false);
}
foo.prototype.bar = function()
{
console.log(this.element.value);
};
new foo("anyInputElement");
答案 0 :(得分:2)
在JavaScript中,它是关于你是实例化还是仅仅调用一个函数。它只是前者的构造函数。正如您可能已经知道的那样,区别在于是否在函数引用之前使用了new
关键字。
这可以控制构造函数中的属性是 的属性。
所以在你的情况下,它们不是构造函数的属性(这是一种无用的思考方式);相反,它们是您实例的属性。
调用函数在window
范围内执行,因此,如果您只是调用函数,this.foo
等将在window
上设置属性。
但是,如果实例化该函数,它们将成为实例上的属性,因为实例是从实例化而不是调用的函数(构造函数)中隐式返回的。所以:
调用:属性在默认上下文window
上设置:
function static_func() { this.foo = 'bar'; }
static_func();
window.foo; //'bar'
实例化:属性在返回的实例
上设置function constructor(val) { this.foo = val; }
var instance = new constructor('bar');
window.foo; //undefined
instance.foo; //'bar'
答案 1 :(得分:0)
所以你很困惑为什么当你把它保存在一个变量中时,以后它不是“这个”?有几个原因可以解释为什么self在后来的keyup事件中并不是“这个”。
当作为<input id="anyInputElement" />
的结果调用keyup事件时,keyup事件的回调函数this
将成为该输入。这是因为已创建新的执行上下文,导致this
被分配给元素。
那么为什么不是self
,而不是输入元素?
执行上下文是基于堆栈的。因此,当父函数foo用new实例化时,它会创建自己的执行上下文。这是keyup回调中使用的执行上下文的父上下文,因为它在堆栈中较低。每个执行上下文还包含词法和变量环境。这些环境包含可用的变量(命名冲突导致变量覆盖词法)。
this
词汇环境包含来自父环境的所有变量,一直到堆栈(这就是为什么function foo(id)
{
var self = this; //parent context
this.element.addEventListener("keyup", function(){
self.bar(); //child context
}, false);
}
可以从任何地方访问的原因)。因此,这里的子执行上下文(在keyup回调中)在其词法环境中包含window
。
self
包含来自父执行上下文的self
的副本。
因此,当使用this
时,即访问的执行上下文(包括词法和变量环境)。这是来自self
的属性的来源。请注意,因为keyup回调创建了自己的执行上下文,所以它还有一个新创建的foo
(这意味着self!=这在keyup事件监听器中)。