在knockout.js视图模型中使用`var self = this`有什么好处

时间:2013-06-18 07:44:16

标签: javascript knockout.js

我在几乎所有的knockout.js视图模型中看到了行var self = this,然后所有局部变量都被引用为self.variableName。与使用this.variableName相比,这有什么好处?

3 个答案:

答案 0 :(得分:39)

通常,使用此方法的主要原因是使当前this可用于子功能或闭包。例如:

var myObject = {
  param: 123,
  method: function(){
    alert( this.param );
  },
  method2: function(){
    setTimeout(function(){
      alert( this.param );
    },100);
  }
}

在上面的调用中myObject.method会为您提供123的正确提示。但是,调用myObject.method2会给您undefined。这是因为与this一起使用的匿名函数中的setTimeout并未引用myObject,这取决于JavaScript解释器,它将指向不同的东西。但是,如果你有:

method2: function(){
  var self = this;
  setTimeout(function(){
    alert( self.param );
  },100);
}

这是有效的,因为当前状态this - 在正确的位置 - 被捕获,并且将始终为可用的每个功能范围引用myObject

问题不仅限于使用setTimeout。在任何你有匿名函数,子函数或闭包的地方,这个技巧都会派上用场。有时人们使用selfthat或更具描述性的内容,具体取决于当前引用所代表的内容。


而不是存储为变量

有一种替代方法可以使用self或任何其他变量来记住"在任何特定点上的状态,那就是" bind"具有特定上下文的匿名或子函数。许多现代解释器现在支持Function.prototype.bind方法,因此可以使用:

var method = function(){
  console.log(this);
};
var methodWithWindow = method.bind(window);
var methodWithDocument = method.bind(document);
var methodWithObject = method.bind({random:"object"});

依次调用每个绑定方法将为您提供以下控制台输出:

Window
Document
Object {random:"object"}

如果您希望支持较旧的浏览器,可以使用polyfill,或者如果您更喜欢更简单的实现,也不必担心绑定参数。绑定代码的基础知识如下:

!Function.prototype.bind && (Function.prototype.bind = function(context){
  var method = this;
  return function(){
    method.apply(context, arguments);
  }
})

那么,初始示例如何使用bind?

method2: function(){
  setTimeout((function(){
    console.log(this); // `this` will be the same as the `this` passed to bind.
  }).bind(this),100);
}

如上所示,一旦绑定,返回的函数(闭包)将保留指定的上下文;所以它可以在任何你想要的地方传递,并且仍然保持对你想要的对象的this引用。这在method2示例中非常有用,因为我们将方法与当前上下文捆绑在一起并将其传递给setTimeout,后者将在稍后执行绑定方法(在我们退出当前块执行后很久)。 / p>

使用self或任何其他变量时也会发生同样的情况。该变量将在函数的作用域链中捕获,并且在最终再次调用该函数时仍然可以进行访问。但是,使用bind的好处是,如果您愿意,可以轻松覆盖上下文,您必须编写自己的特定方法来覆盖self变量。

  

警告:值得注意的是,绑定函数时会返回一个新函数。如果将绑定函数与事件侦听器混合,然后尝试使用原始函数而不是绑定版本删除侦听器,则会导致混乱。

     

另外,因为绑定返回一个新函数,如果你绑定一个绑定函数,你实际上是在一个函数中包含一个函数,与另一个函数。您应该意识到这一点,因为它会影响性能,并且在避免内存泄漏方面会更难管理。我首选的绑定方法是使用带有自己解构方法的闭包(即依赖于self,但确保你有方法来消除它的内容),但这确实需要更多的前瞻性思维,并且在较小的时候不那么重要。 JS项目;或者一个关闭函数绑定 - 特别是如果绑定方法永远不会被任何引用捕获。


没有自我和绑定?

还值得一提的是,有时您可以在不使用bind的情况下获得相同的结果,而是使用apply - 这应该是您可以选择使用的任何内容。主要区别在于函数没有包含任何内容,而调用apply实际上在那里执行函数,然后使用不同的上下文 - 传递给apply的第一个参数。

var externalMethod = function(){
  console.log(this); // will output myObject when called below
};

var myObject = {
  method2: function(){
    externalMethod.apply(this);
  }
};


什么是this

在最近的评论被删除之前,只需详细说明this的详细信息。 this将引用四种内容之一,具体取决于您在其中使用它的功能的调用方式:

myObject.method()

以上将this myObject,除非method已应用.bind(context)操作。在这种情况下,this将是最后绑定的上下文。

unattachedFunction()

除非this已应用window操作,否则将拥有unattachedFunction全局上下文(通常在浏览器环境中为.bind(context))。在这种情况下,this将是最后绑定的上下文。

anyFunction.apply(otherObject)

anyFunction.call(otherObject)

两者的this总是otherObject,因为以这种方式调用会覆盖任何绑定。

new myObject()

this引用myObject的新实例,这将覆盖任何绑定。


简单的思想实验

考虑到以上所有因素,this内的referencedMethod会是什么?

var referencedMethod = myObject.method;
referencedMethod();
  

正确!这将是全球背景。这就是为什么如果你想与其他对象或代码共享方法 - 但仍然保留原始所有者作为上下文 - 你真的需要绑定,或保持与其所有者对象捆绑的功能,以便你可以调用或应用。

答案 1 :(得分:2)

Self用于确保在对象中维护原始this

使用事件处理程序等时会派上用场。

您可以阅读有关此here

的更多信息

第一个答案基本涵盖了它,也显示了一个很好的链接。看看吧。

答案 2 :(得分:1)

用于参考目的。 Javascript下的this行为与其他语言不同。有关详细信息,请查看MDN Docs on this