理解原型和这个

Understanding Prototype and this

本文关键字:原型      更新时间:2023-09-26

据我所知,"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");

在JavaScript中,这是关于你是实例化还是仅仅调用一个函数。只有在前者的情况下,它才是构造函数。您可能已经知道,区别在于new关键字是否在函数引用之前使用。

它控制构造函数中的属性是的属性

所以在你的例子中,它们不是构造函数的属性(这是一种无益的思考它们的方式);相反,它们是实例的属性。

被调用的函数在window作用域中执行,因此,如果您仅仅调用您的函数,this.foo等将在window上设置属性。

如果你实例化了函数,但是,它们成为实例上的属性,因为实例是隐式地从实例化而不是调用的函数(构造函数)返回的。所以:

调用:属性在默认上下文中设置,window:

function static_func() { this.foo = 'bar'; }
static_func();
window.foo; //'bar'

Instantiation:属性被设置在返回的实例

function constructor(val) { this.foo = val; }
var instance = new constructor('bar');
window.foo; //undefined
instance.foo; //'bar'

所以你很困惑为什么当你把它保存在一个变量中,它不是"this"以后?在keyup事件后面,self不是"this"有几个原因。

当keyup事件作为<input id="anyInputElement" />的结果被调用时,keyup事件的回调函数的this将是该输入。这是因为创建了一个新的执行上下文,导致this被分配给元素。

那么为什么分配给thisself不是输入元素呢?

执行上下文基于堆栈。因此,当父函数foo用new实例化时,它创建了自己的执行上下文。这是keyup回调中使用的执行上下文的父上下文,因为它在堆栈中较低。每个执行上下文还包含一个词法和变量环境。这些环境包含可用的变量(命名冲突会导致变量覆盖词法)。

function foo(id)
{
 var self = this;  //parent context
 this.element.addEventListener("keyup", function(){
  self.bar();  //child context
 }, false);
}

一个词法环境包含了从父环境一直到堆栈的变量(这就是为什么window可以从任何地方访问)。因此这里的子执行上下文(在keyup回调中)在其词法环境中包含self

self包含从父执行上下文中复制this

因此,当使用self时,访问的是执行上下文(包括词法和变量环境)。这就是foo属性的来源。注意,因为keyup回调创建了自己的执行上下文,所以它也有一个新创建的this(这意味着在keyup事件侦听器中self != this)。

相关:保存对这个作用域的访问