在 knockout.js 视图模型中使用 `var self = this` 有啥好处 [重复]

Posted

技术标签:

【中文标题】在 knockout.js 视图模型中使用 `var self = this` 有啥好处 [重复]【英文标题】:What's the advantage of using `var self = this` in knockout.js view models [duplicate]在 knockout.js 视图模型中使用 `var self = this` 有什么好处 [重复] 【发布时间】:2013-06-14 08:02:53 【问题描述】:

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

【问题讨论】:

因为this 在每个范围内都会发生变化,但self 将包含默认的this 值。 var self = this? 和 ***.com/questions/962033/… 的可能重复项 【参考方案1】:

通常使用这种方法的主要原因是使当前的this 可用于子函数或闭包。例如:

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

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

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

这是因为this 的当前状态——在正确的点——被捕获,并且对于它可用的每个函数范围总是引用myObject

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

而不是存储为变量

除了使用self 或任何其他变量来“记住” this 在任何特定点的状态之外,还有一种替代方法,那就是将您的匿名函数或子函数与特定上下文“绑定”。许多现代解释器现在都支持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,后者将在稍后执行绑定的方法(在我们退出当前块执行很久之后)。

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

在最近的 cmets 被删除之前,用更多关于 this 的细节来详细说明这个答案。 this 将指四件事之一,具体取决于您在其中使用它的函数的调用方式:

myObject.method()

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

unattachedFunction()

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

anyFunction.apply(otherObject)

anyFunction.call(otherObject)

两者都将始终具有otherObjectthis,因为以这种方式调用将覆盖任何绑定。

new myObject()

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

简单的思维实验

考虑到以上所有因素,thisreferencedMethod 中会是什么?

var referencedMethod = myObject.method;
referencedMethod();

正确!它将是全局上下文。这就是为什么如果你想与其他对象或代码共享方法——但仍保留原始所有者作为上下文——你真的需要绑定,或者将函数与其所有者对象捆绑在一起,以便你可以调用或应用。

【讨论】:

它是指第一个更高级别的功能吗?或者当它在用作函数参数的函数内部调用时,直到字段变量,它会这样做吗? (不好意思使用了C#...基础术语,不知道js中的等价物) this 将引用三件事之一,具体取决于您在其中使用的函数 this 的调用方式:myObject.method() 将具有 thismyObject、@987654382 @ 将有一个全局上下文的this(通常在浏览器环境中为window),而anyFunction.apply(otherObject) 将始终有一个thisotherObject。我提到的前两个将被任何.bind(differentObject) 操作覆盖,而后一个.apply().call() 不会。希望这是有道理的@deadManN 谢谢,但仅与applycall 有关吗?或者它关于以otherObject作为输入的函数,哪个参数优先使用this对象,比如......函数这样做,对这个对象,或者只是参数的存在导致这个,或者特定类型的参数导致它喜欢... x(funcObj) / x(strObj) / Y(classObj) 我不太清楚你的意思@deadManN。在 JavaScript 中调用函数只有三种真正的方法。作为独立函数或包含函数standAlone()var sa = myObject.method; sa(); 的变量,作为对象myObject.method() 的方法或通过call/apply。只有后两者指定了所谓的上下文,即this 所指的内容。对于方法调用,左侧指定的对象用作上下文,因此myObject.method() 表示thismyObject,对于callapply,它是第一个参数用过。 你说得对,谢谢...抱歉语言不好,我不是本地人【参考方案2】:

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

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

你可以阅读更多关于这个here

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

【讨论】:

【参考方案3】:

仅供参考。 Javascript 下的this 的行为与其他语言不同。更多详情请查看MDN Docs on this

【讨论】:

以上是关于在 knockout.js 视图模型中使用 `var self = this` 有啥好处 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 knockout.js 中将 observable 从一个视图模型传递到另一个视图模型

在 knockout.js 视图模型(数组)中存储特定元素

knockout.js remove 不适用于主视图模型中的嵌套视图模型和视图模型

Knockout.js - 封装视图模型并从外部隐藏它们

knockout.js 主视图模型中的一个视图模型(添加项目变得未定义)

使用写入函数时,Knockout JS 可写计算值不会触发另一个计算值