“var self = this”方法背后的原理是什么?

What is the rationale behind the "var self = this" approach?

本文关键字:是什么 背后 方法 self var this      更新时间:2023-09-26

可能的重复项:
JS:var self = this?

查看用 JavaScript 编写的任意代码(例如在 GitHub 上)时,许多开发人员使用 var self = this,然后使用 self 而不是 this 来引用当前对象。

这种方法背后的理由是什么?

this的值是上下文相关的。编写var self = this是一种将this的值保存在一个上下文中以便可以在另一个上下文中使用的方法。

例:

function Test() {
    var self = this;
    console.log(this);
    setTimeout(function() {
        console.log(this);
        console.log(self);
    }, 1000);
}

指纹:

Test {}
Window 11918143#comment15869603_11918143
Test {}

请注意,this的值已更改,但我们仍然可以使用 self 引用原始值。

这是有效的,因为 JavaScript 中的函数"关闭"其词法范围内的变量(这只是一种更技术性的说法,即内部函数可以看到外部函数中声明的变量)。这就是我们写var self = this的原因;变量 self 可用于所有内部函数,即使这些函数直到外部函数返回很久后才执行。

例如,当您在 jQuery 中使用回调时,您可能希望引用父函数的 this 变量,该变量在另一个函数中后采用不同的值:

$('#foo').click(function() {
  var self = this;
  $.get('foo.php', function(data) {
    // In here, self != this
    $(self).text(data);
  });
});

在这种情况下,将$(self)替换为$(this)将不起作用。基本上,您将this存储在变量中以供以后使用。

通常,当您在某些代码中具有嵌套函数声明,但您想从"子"函数内部引用"parent"函数时。

Ext.define('MyPanel', {
    extend: 'Ext.panel.Panel',
    title: 'My Panel',
    initComponent: function() {
        var self = this;
        Ext.applyIf(self, {
            items: [
                {
                xtype: 'button',
                text: 'MyButton',
                handler: function() {
                    console.log(this); //the button
                    console.log(self); //the panel
                }}
            ]
        });
        self.callParent(arguments);
    }
});
Ext.onReady(function() {
    var p = new MyPanel({
        renderTo: Ext.getBody()
    });

});​

例:

http://jsfiddle.net/8F4UN/

让我给出一个更技术性的解释。当您在 Javascript 中访问变量时,解释器会在所谓的作用域堆栈中查找变量的值。您可以将其视为一堆对象。解释器将首先查看堆栈的顶部。如果未在该范围对象中定义变量,它将查看其下的对象。如果它不存在,解释器会向下看另一层,直到它到达堆栈的底部。

最初,堆栈中唯一的范围对象是全局对象。变量要么存在,要么不存在。调用函数时,解释器将一个新对象推送到作用域堆栈上,用于存储局部变量。当您访问 var1 时,解释器将首先查看本地作用域对象。如果它在那里,那么它将使用存储在那里的值。如果不是,它将移动到堆栈中更下方的 scope 对象,这恰好是全局范围。

当您在函数中创建函数时,会发生一些有趣的事情。解释器将创建所谓的"激活对象"。它基本上是外部函数的本地作用域对象的快照。此激活对象与内部函数相关联。调用内部函数时,激活对象被推到本地作用域之前的作用域堆栈上(即本地作用域仍将位于顶部)。访问内部函数中的变量意味着解释器将首先检查局部作用域对象,然后检查激活对象,然后检查全局作用域对象。

根据定义,this 变量始终存在于函数的局部作用域中。它始终引用隐式的第一个参数。调用 plain-o 函数时,编译器将按方式传递 null。变量存在,但指向 null。对此的搜索永远不会超出本地范围对象。

分配给 self 的目的基本上是愚弄解释器,这样它就会超越内部函数的局部范围。当您在内部函数中访问 self 时,解释器不会在本地范围内找到它。因此,它会检查激活对象。假设 self = 此语句发生在创建内部函数之前,则 self 将存在于激活范围对象中,指向外部函数看到的 this 对象。