【问题标题】:Is var self = this; a bad pattern?是 var self = this;一个糟糕的模式?
【发布时间】:2011-05-21 06:10:06
【问题描述】:

我发现自己需要:

var self = this;

在我的 javascript '类'中有很多。虽然这很常见,但感觉有点不对劲。 我希望在这个问题中找到一种更好的方法来处理这个问题,或者让我相信这很好。

这是保持正确绑定的标准方法吗?除非我明确需要“this”,否则我是否应该在任何地方标准化使用“self”。

edit:我确切地知道我为什么需要这个,我只是想知道它是否被认为有点邪恶以及为什么。我知道还有“应用”内置 javascript 函数可以在调用方法时显式定义范围。好点了吗?

【问题讨论】:

  • 我一直使用var that = this,老实说,我什至没有费心研究应用/调用,但现在我读到了这些方法,感谢这个问题!
  • 我个人认为这本身还不错,但表明您可以稍微优化您的设计。

标签: javascript


【解决方案1】:

在带有closures 的javascript 和其他语言中,这可能是一件非常重要的事情。 this 在方法can actually change 中引用的对象。一旦您将 self 变量设置为等于 this,那么 self 将可靠地保持对相关对象的引用,即使 this 稍后指向不同的对象。

与我们使用的许多其他语言相比,这是 javascript 的一个重要区别。我来自 .Net,所以这种类型的东西起初对我来说也很奇怪。

编辑: 啊,好吧,这些你都知道。 (也许对其他人仍然有帮助。)我要补充一点,Apply(和 Call)更多地用于从“外部”使用,为您调用的函数提供您已经知道的特定范围。一旦你进入一个函数并且你将进一步向下级联到闭包中,该技术:

  var self = this;

是锚定您的当前范围的更合适的方式(easyclear)。

【讨论】:

    【解决方案2】:

    这样做很可能是为了在范围即将更改时(在关闭的情况下)保持对this 的引用。我不知道我会认为它本身是一种不好的做法或模式,不。你会在 jQuery 之类的库中看到很多类似的东西,并且在使用 AJAX 时会看到很多类似的东西。

    【讨论】:

      【解决方案3】:

      正如其他人所说:这个“额外变量”是(在某种程度上)了解this 是一个特殊表达式这一事实的唯一方法,因此,它不是一个变量,它不受执行上下文的约束/关闭。

      但是,我认为您要问的(或我真正想回答的)是:

      是否应该将var self = this 放在每个方法/构造函数的顶部?

      总结

      虽然我尝试过一次,并且有同样的问题,但我不再使用这种方法。现在我保留这个结构,以备在闭包中需要访问时使用。对我来说,它增加了一点“嘿,这就是我真正想要的!”我的代码的语义:

      this -> thisself -> this (but really that) in a closure

      问题点菜:

      ...虽然这很常见,但感觉有点不对劲。我希望在这个问题中找到一种更好的方法来处理这个问题,或者让我相信这很好。

      做你觉得对的事。不要害怕尝试一种方法并稍后切换回来(但请尽量在每个项目中保持一致:-)

      这是保持正确绑定的标准方法吗?除非我明确需要“this”,否则我是否应该在任何地方都使用“self”标准化。

      “self”是最常用的名称。如上所述,我更喜欢相反的方法——使用this,除非需要闭包绑定。

      ..如果它被认为有点邪恶,为什么。

      邪恶是一个愚蠢的主观术语(尽管有时很有趣)。我从来没有说过这是邪恶的,只是为什么我不遵循这种方法。有些人告诉我,我不使用分号是“邪恶的”。我告诉他们他们实际上应该提出好的论点和/或更好地学习 JavaScript :-)

      我知道还有“应用”内置 javascript 函数可以在调用方法时显式定义范围。好点了吗?

      apply/call 的问题是您必须在函数调用时使用它们。如果有人 else 调用您的方法之一,这将无济于事,因为 this 可能已经关闭。它最适用于 jQuery 风格的回调,其中 this 是回调的元素/项目等。

      顺便说一句……

      喜欢避免在成员上“需要自我”,因此通常将所有成员函数提升为接收者 (this) 只是“流经”的属性,这通常是“如预期的那样” .

      我的代码中的“私有”方法以“_”开头,如果用户调用它们,那就是它们。当使用原型方法创建对象时,这也更有效(确实是必需的)。但是,Douglas Crockford disagrees 使用我的这种“私有”方法,并且在某些情况下查找链可能会通过注入意外接收器来阻止您:

      在构造函数中使用“self”绑定也会锁定方法的查找链的上限(它不再向上多态!)可能正确也可能不正确。我认为这通常是不正确的。

      编码愉快。

      【讨论】:

      • 很好的答案。您能否详细说明此声明:“我喜欢避免对成员“需要自我”,因此通常将所有成员函数提升为接收者(this)只是“流经”的属性,这通常是“如预期的那样”。你是怎么做到的?
      • @Evert 如果每个方法都是对象的成员,它将/应该以某种形式的obj.member 调用,这通常会确保this 是正确的(因为obj->this(obj)->this(obj)->...)。如果您在帖子中看到 Crockford 链接,您将看到私有方法方法打破了模式,因为私有“方法”现在存储在构造函数的变量中,因此不会在 obj.member 表单中调用。这将在其中抛出this(因为this 只是函数在调用时的接收者——在上面的示例中为obj),除非完成额外的工作。
      • aelf 是窗口对象——我会避免使用保留字,并使用var that = thisvar _self = this
      • @chovy 我从未想过的有趣点。我想我总是通过在我的代码中使用window.x 限定符总是 [除了我很少忘记] 来避免这个问题(而且我从未使用过window.self ..)
      • 邪恶的两倍。将var self = false 放在全局上下文中,然后在需要的方法中添加var self = this;。如果有任何疑问,请写信(self || this).method(...)。这是糟糕的编码,但感觉很好。
      【解决方案4】:

      是的,这是标准方式。

      Function.apply()Function.call() 可以提供帮助,但并非总是如此。

      考虑以下

      function foo()
      {
        var self = this;
        this.name = 'foo';
      
        setTimeout( function()
        {
          alert( "Hi from " + self.name );
        }, 1000 );       
      }
      
      new foo();
      

      如果您想这样做,但避免使用 self 之类的变量,而改用 call()apply()... 好吧... 你看看它并开始尝试,但很快就会意识到你就是不能。 setTimeout() 负责 lambda 的调用,使您无法利用这些备用调用样式。你最终还是会创建一些中间变量来保存对对象的引用。

      【讨论】:

      • 对不起,如果我误解了,但如果你这样做,它会起作用:setTimeout( (function() { alert( "Hi from " + this.name ); }).apply(this), 1000 ); }
      • @drodsou 不,您的代码不起作用,请查看this JSBin。它因语法错误而失败,因为您不能在 JS 中将某些内容包装在“()”中。如您所见,window.setTimeout 不返回函数/对象,而是返回表示计数器 id 的“数字”类型的原语。
      • @Peter Bailey 实际上有another way,不过我并不是说这是一个更好的解决方案。
      • @drodsou 使用 apply(this) 将立即执行函数,因此返回 undefined 作为 setTimeout 的第一个参数,但是有一个绑定函数:window.setTimeout(function () { alert("Hi from "+ this.name); }.bind(this), 1e3);
      • 所以......我看到这个的方式:使用 bind 给出的代码比这个答案中给出的代码短:)。所以这个答案是错误的。 “但并非总是如此”具有误导性。
      【解决方案5】:

      我喜欢。它是“自我”解释的。道格拉斯·克罗克福德对此有话要说。他说使用“that”是惯例。如果您快到 yui-theater 并观看他关于 Javascript 的视频,您可以免费看到 Crockford。

      【讨论】:

      • 感谢您的反馈。我想我明白你的意思了。但是,我不认为,这个问题可以在没有上下文的情况下回答。我碰巧喜欢道格拉斯提出的背景:)
      【解决方案6】:

      这是保持正确绑定的标准方法吗?

      在 JavaScript 和类/实例系统方面没有标准。您必须选择您喜欢的对象模型类型。这是another link 给背景专家;结论:没有结论。

      通常在闭包中保留一个副本var self= this;(*) 与围绕闭包构建的对象模型以及每个方法的每个实例副本密切相关。这是一种有效的做事方式;效率稍低,但通常工作量也比替代方案少一些,即围绕原型构建的对象模型,使用thisapply() 和 ECMAScript 第五版的bind() 来获取绑定方法。

      当您在同一代码中混合了两种样式时,更可能被视为“邪恶”。不幸的是,很多常见的 JS 代码都会这样做(因为让我们面对现实,没有人真正了解 JavaScript 奇怪的原生对象模型)。

      (*: 我通常使用that 而不是self;你可以使用任何你喜欢的变量名,但是self 作为一个指向窗口本身。)

      【讨论】:

        【解决方案7】:

        我认为在每种方法中始终包含var self = this 是有理由的:人为因素。

        它经常被需要,以至于你最终会得到一堆方法来访问this 和其他使用self 来实现相同目的的方法。如果你将代码从一个移到另一个,你会突然得到一堆错误。

        同时,当我不需要或添加var self = this 时,出于习惯,我会心不在焉地写self.foo。因此,我认为养成始终包含它的习惯是有意义的,无论是否需要。

        唯一的麻烦是...thisselfthat 都是你代码上的丑陋痘痘,我有点讨厌它们。所以我认为最好尽可能避免使用委托方法,这样您就可以避免在绝大多数情况下使用thisthatself,并在您可能会求助于@987654333 时使用.bind(this) @/that。无论如何,在原型上使用委托实际上会为您节省大量内存是非常罕见的。

        这种方法的一个很好的副作用是您不必在所有私有变量前加上 _,因为它们将是真正私有的,并且公共属性将由领先的 this. 调用,使得您的代码更具可读性。

        正如 bobince 所说,var that = this 更好,因为它不会影响window.selfself = this 对我来说听起来不那么尴尬,但有时您会收到诸如 property myMethod not found on global 之类的令人困惑的错误消息,因为您忘记了 self = this 行。

        【讨论】:

        • 您能否提供一个 jsfiddle 来说明您将 self 替换为 .bind(this) 的想法?
        • window.setTimeout(function () { this.$btnAccept.tooltip('show'); }.bind(this), 256);
        【解决方案8】:

        我只想指出'self'相当于'window',尝试将window === self输出到控制台。您应该将此模式与“that”或类似变量名的名称一起使用,避免使用“self”,因为它已经被浏览器使用(一个错误,您将自己创建一个全局变量)。 尽管听起来很奇怪,但最好使用“that”作为它的名称,因为其他开发人员会立即知道您在代码中试图完成什么,避免使用非标准的变量名。 我认为这是一个重要的说明,但它只在一条评论中提到,所以我想让它更明显。

        【讨论】:

        • 尝试使用 self 对象在浏览器中创建一个全局变量并发布一个小提琴。在我的浏览器(Chromium)中,这不起作用,因为如果您使用“self = ...”而不使用“var”,它将在“window”上定义一个属性“self”。
        • 我不确定您为什么要创建名为“self”的新全局变量。在 JavaScript 中,您当然可以修改 JavaScript 本身,但这样做时您应该非常小心,因为当您向其他开发人员提供您的代码时,他们会期待 JavaScript 的“标准版本”。当您将某些内容分配给“自我”时,实际上是在覆盖它,我会避免这样做。我只是说,当你比较默认的 window 对象和 self 时,它们默认是同一个对象。换句话说,“self”和“window”是同义词
        • (一个错误,你将自己创建一个全局变量)
        【解决方案9】:

        刚刚遇到这个问题,因为我的同事沉迷于自我/那个变量,我想了解为什么......

        我认为现在有更好的方法来处理这个

        function () {}.bind(this);      // native
        _.bind(function () {}, this);   // lodash
        $.proxy(function () {}, this);  // jquery
        

        【讨论】:

          【解决方案10】:

          6年过去了,我有一些话要补充:

          bind() 现在很常见,可以在任何地方使用。我经常使用它作为替代品。有时感觉更清晰。我仍然偶尔使用var self = this;。不过。

          箭头函数正在慢慢变得可行。语法有点短,这很好,但我认为杀手级功能确实是默认情况下它们总是绑定到父作用域。

          这个:

          var self = this;
          var foo = function(a) {
          
            return self.b + a;
          
          };
          

          现在可以写成:

          var foo = a => this.b + a;
          

          这是箭头函数的“最乐观”用法,但它非常可爱。

          总结一下,没有什么问题:

          var self = this;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-07
            • 2011-01-13
            • 1970-01-01
            • 2015-06-01
            • 2011-08-28
            • 2022-07-13
            相关资源
            最近更新 更多