变量“me = this”的价值是什么?

33

我在 ExtJS 源代码中到处发现了这种模式。

method: function() {
  var me = this;
  ...
  me.someOtherMethod();
}
为什么他们不直接使用this?在定义me时,除了不需要输入2个字符之外,是否有一些优势(通常是这样)?我可以理解如果他们尝试通过闭包来维护上下文,但是在没有闭包的情况下也会这样做,例如Ext.panel.Panel中的一个示例。
disable: function(silent) {
    var me = this;

    if (me.rendered) {
        me.el.addCls(me.disabledCls);
        me.el.dom.disabled = true;
        me.onDisable();
    }

    me.disabled = true;

    if (silent !== true) {
        me.fireEvent('disable', me);
    }

    return me;
},

我曾经使用这种做法的唯一情况是在新的上下文中。你能提供一个具体的代码片段,在那种情况下它没有被使用吗? - Steven
我希望人们继续对这些答案进行投票。我选择了Daniel的答案,因为他最先回答并且回答符合我的问题精神。 - Hemlock
也许有人真的不喜欢隐式的 this 这个想法? - Fake Name
10个回答

40

如果你的库在没有嵌套闭包/回调可能有自己的this值的情况下进行这样的操作,那么这只是他们决定在方法中遵循的"实践"、"风格"或"约定"。没有编程上的理由必须始终这样做。

在你现在添加到问题中的具体代码示例中,我不知道除了常见的编码风格之外还有其他原因。这段代码也可以生成相同结果但代码略微较小:

disable: function(silent) {

    if (this.rendered) {
        this.el.addCls(this.disabledCls);
        this.el.dom.disabled = true;
        this.onDisable();
    }

    this.disabled = true;

    if (silent !== true) {
        this.fireEvent('disable', this);
    }

    return this;
},
当涉及到回调或闭包时,通常会这样做是因为在方法内部使用了回调,而他们仍然想要引用 this,但是这些回调将拥有它们自己的this值,因此进行如下赋值操作:
var me = this;

或者在我看到的其他代码中更常见的是:

var self = this;

闭包是一种在回调函数中保留对对象访问权限的方式,即使回调函数中的this具有不同的值。

以下是一个通用示例:

document.getElementById("myButton").onclick = function () {
    var self = this;       // save reference to button object use later
    setTimeout(function() {
        // "this" is not set to the button inside this callback function (it's set to window)
        // but, we can access "self" here 
        self.style.display = "none";    // make button disappear 2 seconds after it was clicked
    }, 2000);
};

5
我也是这样想的,但是原帖作者自己观察到在回调函数中访问this是常见做法。从我的阅读来看,他特别想知道即使没有涉及新的上下文,为什么还会使用它。 - Steven
好的,我在我的答案中添加了一条评论,与在没有回调/闭包时执行它有关。一个具体的代码示例将会在那种情况下产生更有意义的答案。 - jfriend00
4
这并非出于编程原因,而是为了减小文件大小。this 无法缩短,但 me 可以。 - Brian Moeskau
3
@jfriend00,我不是在提出我的观点。我正在明确陈述为什么在Ext中这样做。 - Brian Moeskau
即使这并没有回答 OP 的确切问题,这仍然是一个非常有价值的答案,特别是因为最后一个例子。谢谢 @jfriend00 - Chris Schmitz
显示剩余2条评论

24

一个原因是因为在代码压缩时,me 可以比 this 更短。


6
当你压缩代码时,"me" 可以变成只有 'x' 或者 'y',或者比 'this' 更短的东西。但是压缩工具不会修改 'this' 关键词。 - Hyangelo
所以如果他们要使用this超过3次,那么会有一些小优势。这里可能有点门道。 - Hemlock
我认为这正是它的原因。我能想到的另一件事就是提供一个比“this”更具描述性的名称,尽管问题代码中的“me”并没有真正提供这种好处。 - user113716
5
这确实听起来像一种可能的好处。通过使用12个字符声明最小化版本的var a=this;\n,并且通过使用a代替this可以节省3个字符,如果有超过四个对this的引用,则可以节省字节。如果只有一两个对this的引用,则会浪费一些字节。但我想知道这是否是真正的动机,还是只是一种通用的方法实现风格,以保持所有方法的一致性,即使是那些嵌套闭包的方法。 - jfriend00
是的,这是主要原因。在大型框架中,这会导致压缩文件大小的显著变化。 - Brian Moeskau
1
为什么JavaScript压缩器没有执行这个优化呢?这个理由对我来说似乎有些牵强,这只会减少文件大小的1-2%左右,并不值得手动混淆原始代码。 - Lie Ryan

14
除了样式原因和代码压缩原因,我决定查看性能,以查看在使用 thisself 时哪个更快。我创建了这个 jsperf 测试

就我所知,在我尝试的任何现代浏览器甚至是IE6中,使用本地变量如 self me 与使用 this 相比几乎没有任何性能差异。Chrome 使用 self 稍微比其它浏览器快一些,但它们太接近无法区分。我认为我们可以排除任何性能原因。这是我看到的结果截图:

enter image description here


4

这个问题很可能与闭包函数有关,例如当您在注册回调时将其作为参数。在这种情况下,“this”可能具有完全不同的值,因此它们需要使用“me”。


4
有时候在闭包中保持作用域,但大多数情况下(如所示例子),是为了允许缩小代码。因为me可以缩小为一个字符,而this则无法更改。在给定函数中使用this约3或4次后,这变得很重要(少于此数量可能会导致额外的声明代码增加几个字节)。就是这么简单 - 它与编程风格或奇想无关。

2

根据你刚刚添加的 Ext.panel.Panel 示例,除非我的 JavaScript 变量理解非常错误,否则在此处不进行赋值对代码执行没有任何影响。

唯一可能存在的影响是样式。

尽管我认为这有点过度设计,但如果您想添加需要在此上下文中访问 this 的回调函数,则无需返回更改所有 thisme。毕竟,键入:s/很难。


2
实际上,尽管这可能不是动机,但出于样式考虑这样做是有道理的。许多样式惯例旨在使人们更难忘记某些东西,例如总是在else块周围放置{ },即使它只是一个语句。重新分配"this"也会产生类似的影响,因为初学JavaScript的程序员会使闭包“正常工作”的比例更高。

1

除了在闭包中保留上下文之外,我不知道使用该模式是否有任何程序上的区别。也许这只是ExtJS正在使用的一种约定。

此外,正如Daniel所指出的那样,这可能是为了在缩小代码时进一步缩短代码。像ExtJS、jQuery等库非常关心文件大小,使用这种技术可能会产生足够的文件大小节省。

例如,1000个'this',假设1个字符=1个字节,就是4kb。使用上述技术可能会节省2或3 kb。

更新:进行了一个小实验。

var test = {
  a : function() {
     this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
  },
  b : function() {
      this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
  },
  c : function() {
      this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
     this.x='';
      this.x='';
     this.x='';
     this.x='';
  }
}

压缩成

var test={a:function(){this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x=""},b:function(){this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x=""},c:function(){this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x="";this.x=""}}

var test = {
  a : function() {
     var me=this;
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
  },
  b : function() {
      var me=this;
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
  },
  c : function() {
      var me=this;
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
     me.x='';
      me.x='';
     me.x='';
     me.x='';
  }
}

压缩成

var test={a:function(){var a=this;a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x=""},b:function(){var a=this;a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x=""},c:function(){var a=this;a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x="";a.x=""}}

这大约相当于多或少10%的字符(当然,这取决于您的代码块作用域中重复使用了多少“this”)。


百分比变化更多取决于函数中有多少其他代码。你的例子几乎没有其他代码,所以百分比变化会被放大。我们正在谈论每个函数节省一小部分字节,当你克服了声明a的附加开销后,每次使用“this”时最多可以节省3个字节,然后将其替换为“a”。 - jfriend00
如我所述,节省的实际情况取决于您在代码中的每个作用域内使用“this”关键字的频率。我的意思是您可以将多少次“this”替换为“me”。“this”关键字本身出现的次数并不决定您可以替换它的次数(例如,在每个函数中使用1个“this”)。 - Hyangelo

1

在使用ExtJs时,我并没有发现这种约定很有用。我没有经常使用闭包。当在其他框架中工作,比如AngularJs时,这种约定为我节省了很多痛苦和苦难。错误地获取你的作用域是一个耗时的bug。一旦我开始使用这个约定,我再也没有弄错过作用域。


1

针对ExtJS框架。

ExtJS有自己的机制来处理问题Javascript作用域,缩小代码是使用var me = this唯一原因。

关于此主题还有更多细节,请参阅这个Sencha论坛帖子


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接