我很好奇,通常哪种方法更可取,或者即使有偏好,也可以给出以下两个选择:

$.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", this);
    }.bind(this)
});


如果我在函数内部在需要“ this”和外部作用域的“ this”的地方,我将分配一个变量,但是我通常更喜欢绑定以使变量的使用范围限制为尽可能少的行。

评论

虽然此问题最初以“不清楚”结束(大概是由于缺乏上下文),但应注意的是,按照今天的标准,它将以“假设”代码结束,并且进一步的标志将被拒绝。

#1 楼

IE8和Safari5不支持var self = this;的东西。如果您打算建立一个支持旧版浏览器的库或代码,那么bind将更适合跨浏览器使用。
有时,回调在执行时会绑定到特定的上下文,例如jQuery的var self = this,其中$.each是当前项目。如果您不想丢失此上下文,但仍然希望拥有父上下文,则使用this的另一个原因。调用var self = this;会创建带有强制上下文的全新函数。这个函数创建步骤可能是一个大规模的性能问题,尤其是如果您在循环内调用bind

支持bind的原因


性能不会如果您只创建了一个绑定函数一次并在多个地方重复使用,将是一个问题。就像您可以创建一个绑定函数并在一个循环中调用该绑定函数一样(而不是在循环中调用bind)。
bind还可以减轻您一直在显式地执行bindcall(customContext)的麻烦。如果在当前范围内找不到变量,则寻找变量会造成性能问题,尤其是在非常深的范围内。您可能已经听说过“通向本地更好”的提示。

我并不是说apply(customContext)不好(我自己广泛使用了它们)。它只需要在正确的情况下使用。此外,两者的性能问题都可以忽略不计,只有当您打算在不到16ms的时间内完成工作(以60fps进行工作)时,才能看到它们。

评论


\ $ \ begingroup \ $
请注意,第一个可以使用es5-shim解决。使用self需要对回调进行封闭,但是我还没有调查a)如果没有封闭就没有封闭,b)有多少影响。
\ $ \ endgroup \ $
– David Harkness
2014年5月15日20:29

\ $ \ begingroup \ $
这一切都取决于代码在做什么以及js引擎,但是我猜想,关闭它会更昂贵。 IMO,您应该只使用自己认为最好的东西,而不用担心微优化。
\ $ \ endgroup \ $
–pllee
2014年5月15日21:46

\ $ \ begingroup \ $
@pllee我相信bind返回的函数也是一个闭包,因此这并不是var self = this的标记。
\ $ \ endgroup \ $
–wingedsubmariner
2014年5月16日下午4:59

\ $ \ begingroup \ $
经过研究后,闭包比大多数js引擎中的bind绑定要快得多,开销仍然很小,我会坚持您喜欢的。
\ $ \ endgroup \ $
–pllee
2014年5月16日14:11

\ $ \ begingroup \ $
@pllee你是对的。自关闭比绑定快:jsperf.com/bind-vs-self-closure
\ $ \ endgroup \ $
– Harish Anchu
2015年4月11日在7:45

#2 楼

只是添加另一种替代方法,而不是做一个

var self = this;
something( function () {
    // callback stuff
} );


一个人也可以这样做:

( function( self ) {
    something( function () {
        // callback stuff
    } );
} )( this );


是更好吗?这可能取决于。缺点是另一个范围和更深层次的缩进。

一个好处是它是自包含的,新作用域避免了混乱的作用域,尽管您可以争辩说,在设计良好的代码中,在一个作用域中总不应有太多的代码。

还可以说它不太可读,尽管我个人认为bind( this )确实更具可读性。

我只想指出另一种选择,因为它具有更多的可读性。可供选择的选项通常是一件好事。

#3 楼

如果您不需要引用原始bind上下文,则使用简单的经验法则即可。如果需要原始this上下文,请显然使用this变量。

 $.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", this);
    }.bind(this)
});


vs

var me = this;
$.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", me);
    }
});


使用绑定与self变量相比,它稍微更简洁易读,但另一种方法确实没什么大不了的。

#4 楼

关于self特别要注意的一件事;默认情况下,selfwindow的别名。如果您使用var self覆盖它,那很好,但是如果您忘记添加该行,而在内部范围中使用self并假设它引用的是外部范围,则可能会出现一些难以跟踪的讨厌的错误出于这个原因,我倾向于使用其他一些标识符:that_this,一些表示其类型的变量,例如app,如果它引用的是我正在所谓的“应用程序” ,如果是视图等,则为view。在这种情况下,只要您处于严格模式或适当地使代码反对使用未定义的变量,就可以得到通知,如果您忘记添加该别名。 >

评论


\ $ \ begingroup \ $
我倾向于使用我,但我同意最好使用一个实际有意义的名称。
\ $ \ endgroup \ $
–戴夫·范·登·艾恩德
2014年10月10日9:36



\ $ \ begingroup \ $
我使用的是LMAO
\ $ \ endgroup \ $
–BigName
17 Mar 20 '17 at 14:26

#5 楼

根据您正在执行的操作,使用bind的速度会稍微慢一些。我在思考是否最好关闭一组变量或将它们作为参数传递并绑定(它们永远不会改变)时问自己一个问题。

这是我编写的用于对此进行测试的代码出来。您可以更改IJ的值来调整环路。当涉及到实际执行时,它们的速度相当(关闭快一点)。除非当然没有优化程序,否则关闭速度要快4倍左右。但是,绑定的实例化速度要慢2-3倍。

这些测试是在Firefox 33中进行的




 function q(a, b){
  var a = {a:a}, b = {b:b};
  return {
    p:function(){ return a.a + b.b; },
    s:function(){ return a.a - b.b; },
    m:function(){ return a.a * b.b; },
    d:function(){ return a.a / b.b; },
    get_a:function(){ return a.a; },
    get_b:function(){ return b.b; },
    set_a:function(v){ a.a = v; },
    set_b:function(v){ b.b = v; },
  };
}

var I = 1000, J = 100;
var i, j;
var t0 = performance.now()
for(i = 0; i < I; i++){
  var k = new q(5, 6);
  for(j = 0; j < J; j++){
    k.p() + k.s() + k.m() + k.d();
  }
}
var t1 = performance.now();

document.write(t1 - t0)
document.write("<br/>")

var p;

(function(){
  function abp(a,b){ return a.a + b.b; }
  function abs(a,b){ return a.a - b.b; }
  function abm(a,b){ return a.a * b.b; }
  function abd(a,b){ return a.a / b.b; }
  function ga(a){ return a.a; }
  function gb(b){ return b.b; }
  function sa(a,v){ a.a = v; }
  function sb(b,v){ b.b = v; }
  function w(a, b){
    var a = {a:a}, b = {b:b};
    var m = {};
    m.p = abp.bind(m,a,b);
    m.s = abs.bind(m,a,b);
    m.m = abm.bind(m,a,b);
    m.d = abd.bind(m,a,b);
    m.get_a = ga.bind(m,a);
    m.get_b = gb.bind(m,b);
    m.set_a = sa.bind(m,a);
    m.set_b = sb.bind(m,b);
    return m;
  }
  p = w;
})();

var t2 = performance.now()
for(i = 0; i < I; i++){
  var k = new p(5, 6);
  for(j = 0; j < J; j++){
    k.p() + k.s() + k.m() + k.d();
  }
}
var t3 = performance.now();

document.write(t3 - t2) 





TL; DR:.bind较慢。

评论


\ $ \ begingroup \ $
这是一个非常短视的测试。您正在同一范围内执行这些函数,这在某种程度上破坏了这两种方法的全部目的。如果要进行真正的性能测试,请在将函数传递到较远范围的地方进行。这是更现实的做法,因为这是大多数人使用其中一种方法的原因,并且更加公平,因为获取通过封闭关系引用的价值的成本将更高。
\ $ \ endgroup \ $
–狗
15年8月22日在1:25

\ $ \ begingroup \ $
@Dogs,一个真实性能测试将涉及测试真实软件的性能,而不是人为的测试脚本。我认为我写的任何短脚本都是人为的,不一定具有代表性。我不确定如何创建“远距示波器”,如何测量示波器距离?
\ $ \ endgroup \ $
–BlindWanderer
16-4-21在2:14



#6 楼

由于尚无人提及。 jQuery的代理-一种有效的跨浏览器解决方案:

$.ajax({
    url: '/echo/json/',
    success: $.proxy(function(){
        console.log(this === window); // true
    }, this)
});


this通常会引用成功回调中的jqXhr对象。

http:/ /jsfiddle.net/thLhh54q/