我怎么知道何时在JS中的函数上使用.bind()? [英] How do I know when to use .bind() on a function in JS?

查看:76
本文介绍了我怎么知道何时在JS中的函数上使用.bind()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(我知道这个问题,但是答案并不能完全告诉我我需要知道的内容.)

(I'm aware of this question, but the answers don't quite tell me what I need to know.)

我遇到了需要使用 .bind() 以便将this或本地/类变量传递给函数.但是,我仍然不太清楚何时需要它.

I've come across cases where I need to use .bind() on a function in JavaScript in order to pass this or local/class variables to a function. However, I still don't really know when it's needed.

确切地知道什么时候this或局部/类变量何时将在函数中可用的标准是什么?您对此有何看法?

What is the criteria for knowing when this or local/class variables will or will not be available in a function, exactly? How do you reason about this?

例如:

  • 创建,包装或传递新的匿名function() { }时是什么?
  • 使用class成员函数,class getter/setter函数或老式的prototype.function成员函数"(作为类的函数)时?
  • 在全球范围内?
  • forforEach循环中,还是在它们的任何变体中?
  • 在闭包中是外部函数还是内部函数?
  • 在各种JS操作中,例如Array.prototype.forEach.call()[].forEach.call()?
  • 在各种JS库和脚本中,它们可能具有自己的事物自定义实现?
  • When a new anonymous function() { } is created, wrapped, or passed around?
  • When using a class member function, a class getter/setter function, or an oldschool prototype.function "member function" (of a function acting as a class)?
  • In the global scope?
  • In a for or forEach loop, or any of their variants?
  • In a closure outer or inner function?
  • In various JS operations like Array.prototype.forEach.call() or [].forEach.call()?
  • In various JS libraries and scripts, which may have their own custom implementation of things?

我问的主要原因是要意识到潜在的陷阱,避免不得不依靠反复试验.

The main reason I ask is to be aware of potential pitfalls and to avoid having to rely on trial and error.

推荐答案

信用至 T.J. Crowder Zapparatus 给出了答案,它们提供了有用的信息.这四个答案/文章也很有帮助: 1 3 4

Credit to T.J. Crowder and Zapparatus for their answers, which provided helpful info. Also helpful were these 4 answers/articles: 1 2 3 4

但是,这些要么不完全完整和/或very之以鼻.因此,我决定将我的所有发现以及代码示例组合成一个答案.

在确定this或局部/类变量在函数中是否可用时,需要考虑多个因素:

There are several considerations to factor in when determining whether this or local/class variables will be available in a function:

  • 函数的包含范围
  • 呼叫链的直接前辈
  • 该函数是直接调用还是间接调用

注意:还存在严格模式(产生undefined而不是window对象)和箭头功能(不会从包含范围更改this).

Note: there is also strict mode (which yields undefined's rather than window objects) and arrow functions (which do not change this from the containing scope).

以下是明确的规则:

  • 默认情况下,this是全局对象,在浏览器世界中为window.
  • 在全局范围内的函数中,this仍为window,不会更改.
  • class或函数类(new function() { })中的成员函数内部,函数类的原型(funcClass.prototype.func = function() { })中,在相邻成员函数使用this调用的函数内部或内部映射到对象({ key: function() { } })或存储在数组([ function() { } ])中的函数,如果直接使用类/对象/数组作为调用链中的前身直接调用该函数 (class.func()this.func()obj.func()arr[0]()),this引用类/对象/数组实例.
  • 在任何闭包的内部函数(函数中的任何函数)内部,返回的函数内部,在以普通变量引用作为其调用链中前身的函数之前的函数内(无论其实际位于何处!)或在间接调用的函数(即传递给函数(例如.forEach(function() { }))或设置为处理事件的函数)内,this还原为window 调用者可能已将其绑定到(例如,事件可能会将其绑定到触发对象实例).
    • 但是...有一个例外...:如果在class的成员函数中(并且仅在class,而不是函数类中),如果其中的函数丢失了this上下文(例如,通过作为闭包的内部函数),它变为undefined,而不是window ...
    • By default, this is the global object, which in browser world is window.
    • Inside a function in the global scope, this will still be window, it does not change.
    • Inside a member function within a class or function-class (new function() { }), inside a function-class's prototype (funcClass.prototype.func = function() { }), inside a function called by a neighboring member function with this, or inside a function mapped in an object ({ key: function() { } }) or stored in an array ([ function() { } ]), if the function is called directly with the class/object/array as the immediate predecessor in the call chain (class.func(), this.func(), obj.func(), or arr[0]()), this refers to the class/object/array instance.
    • Inside any closure's inner function (any function within a function), inside a returned function, inside a function called with a plain variable reference as its immediate predecessor in the call chain (regardless of where it actually lives!), or inside a function called indirectly (i.e. passed to a function (e.g. .forEach(function() { })) or set to handle an event), this reverts back to window or to whatever the caller may have bound it to (e.g. events may bind it to the triggering object instance).
      • There is... however... one exception...: if inside a class's member function (and only a class, not a function-class), if a function within that loses its this context (e.g. by being a closure's inner function), it becomes undefined, rather than window...

      这是 JSFiddle ,其中包含大量代码示例:

      Here is a JSFiddle with a bunch of code examples:

      outputBox = document.getElementById("outputBox");
      
      function print(printMe = "") {
      	outputBox.innerHTML += printMe;
      }
      
      function printLine(printMe = "") {
      	outputBox.innerHTML += printMe + "<br/>";
      }
      
      var someVar = "someVar";
      
      function func(who) {
      	printLine("Outer func (" + who + "): " + this);
        var self = this;
        (function() {
        	printLine("Inner func (" + who + "): " + this);
          printLine("Inner func (" + who + ") self: " + self);
        })();
      }
      func("global");
      printLine();
      func.call(someVar, "someVar");
      
      printLine();
      
      function funcTwo(who) {
      	printLine("Outer funcTwo (" + who + "): " + this);
        var self = this;
        return function funcThree() {
        	printLine("Inner funcThree (" + who + "): " + this);
          printLine("Inner funcThree (" + who + ") self: " + self);
        };
      }
      funcTwo("global")();
      printLine();
      f = funcTwo("global f");
      f();
      printLine();
      funcTwo.call(someVar, "someVar")();
      
      printLine();
      
      object = {
        func: function(who) {
          printLine("Object outer (" + who + "): " + this);
          var self = this;
          (function() {
            printLine("Object inner (" + who + "): " + this);
            printLine("Object inner (" + who + ") self: " + self);
          })();
        }
      }
      object.func("good");
      printLine();
      bad = object.func;
      bad("bad");
      
      printLine();
      
      function funcClass(who) {
      	printLine("funcClass (" + who + "): " + this);
      }
      funcClass.prototype.func = function() {
      	printLine("funcClass.prototype.func: " + this);
        self = this;
        (function() {
          printLine("funcClass.func inner: " + this);
          printLine("funcClass.func inner self: " + self);
        })();
      }
      fc = funcClass("bad");
      printLine();
      fc = new funcClass("good");
      fc.func("good");
      
      printLine();
      
      class classClass {
      	constructor() {
        	printLine("classClass constructor: " + this);
        }
        func() {
        	printLine("classClass.func: " + this);
          self = this;
          (function() {
          	printLine("classClass.func inner: " + this);
            printLine("classClass.func inner self: " + self);
          })();
        }
        funcTwo() {
        	this.func();
        }
      }
      cc = new classClass();
      cc.func();
      printLine();
      printLine("Calling funcTwo:");
      cc.funcTwo();
      
      printLine();
      
      [0].forEach(function(e) {
      	printLine("[0].forEach: " + this);
        printLine("[0].forEach someVar: " + someVar);
      });
      [0].forEach(function(e) {
      	printLine("[0].forEach with [0]: " + this);
      }, [0]);
      
      printLine();
      
      arr = [
      	function(who) {
        	printLine("Array (" + who + "): " + this);
        },
        1,
        10,
        100
      ];
      arr[0]("good");
      arrFunc = arr[0];
      arrFunc("bad");
      
      printLine();
      
      var button = document.getElementById("button");
      button.onclick = function() {
      	printLine("button: " + this);
      }
      button.click();
      button.onclick = func;
      button.click();
      
      setTimeout(function() {
      	printLine();
      	printLine("setTimeout: " + this);
        printLine("setTimeout someVar: " + someVar);
      }, 0);
      
      setTimeout(fc.func, 0);
      setTimeout(cc.func, 0);

      <input id="button" type="button" value="button"/>
      <br/><br/>
      <div id="outputBox" />

      结论:是的,这很简单.

      Conclusion: So yeah that's pretty simple.

      这篇关于我怎么知道何时在JS中的函数上使用.bind()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆