当你传递'this'作为参数时

noo*_*eed 6 javascript bind this

我正在努力学习this,这让我有点困惑:

var randomFunction = function(callback) {
    var data = 10;
    callback(data);
};

var obj = {
    initialData:  20,
    sumData: function(data) {
        var sum = this.initialData + data;
        console.log(sum);
    },
    prepareRandomFunction: function() {
        randomFunction(this.sumData.bind(this));
    }
};

obj.prepareRandomFunction();
Run Code Online (Sandbox Code Playgroud)

是否this设计为自己设置在代码中首次呈现的位置?例如,在我的例子中,我成功地使用它来引用obj并绑定函数obj,但是因为this它被作为回调函数传递,所以阻止它被设置randomFunction为什么(即什么阻止它从字面上传递"这个.sumData.bind(this)"这样this设置为randomFunction从那里调用时?"

我是一个努力学习的菜鸟.谢谢.

更新 我并不是一般都在询问它是如何工作的(我不认为).我很想知道为什么this在我将其定义为我的randomFunction调用的参数的地方设置,而不是在其中callback调用的地方randomFunction.我可能是错的,但如果我要换掉我现在this.sumData.bind(this)callback(data)那个,我想我会得到不同的结果.是不是因为callback是一个参考this.sumData.bind(this),当它被首先定义(何thisobj)?


我想我已经通过这个场景了解了this它在执行时设置的情况.它不会作为参数传递,以便稍后在该行调用参数时进行设置.

jfr*_*d00 22

this函数调用内部根据函数的调用方式设置.设置有六种主要方式this.

  1. 正常函数调用: 在正常函数调用中,例如foo(),this设置为全局对象(window在浏览器中)或undefined(在Javascript的严格模式下).

  2. 方法调用: 如果调用某个方法obj.foo(),则将this其设置为obj函数内部.

  3. .apply()或.call(): 如果.apply()或者.call()使用,则this根据传递给.apply()或设置的内容进行设置.call().例如,你可以做foo.call(myObj),并导致this被设置为myObj内部foo()针对特定的函数调用.

  4. 使用new: 如果使用new诸如之类的函数调用new foo(),则会创建一个新对象,并foo使用thisset设置为新创建的对象来调用构造函数.

  5. 使用.bind(): 当使用.bind()新的存根函数时,从内部用于.apply()设置this传递指针的调用返回.bind().仅供参考,这不是一个不同的案例,因为.bind()可以实施.apply().

  6. 使用ES6 Fat Arrow函数通过ES6 +中的箭头语法定义函数将绑定当前的词汇值this.因此,无论函数在其他地方如何调用,this解释器都会将值设置this为定义函数时的值.这与所有其他函数调用完全不同.

有一种第七种方法,通过回调函数,但它实际上不是它自己的方案,而是调用回调的函数使用上述方案之一,并确定this调用回调时的值.您必须查阅调用函数的文档或代码,或自行测试以确定this将在回调中设置的内容.


在Javascript中要理解的重要一点是,Javascript中的每个函数或方法调用都为其设置了一个新值this.并且,设置的值取决于函数的调用方式.

因此,如果将方法作为普通回调传递,则默认情况下,该方法不会被调用obj.method(),因此不会this为其设置正确的值.您可以使用.bind()解决该问题.

知道某些回调函数(例如DOM事件处理程序)的调用具有this调用回调函数的基础结构所设置的特定值也很有用.在内部,他们都使用.call().apply()所以这不是一个新规则,但需要注意.回调函数的"契约"可能包括它如何设置值this.如果未明确设置值this,则将根据规则#1进行设置.

在ES6中,通过箭头函数调用函数,保持当前的词法值this.这里的数组函数保持词汇的一个例子thisMDN:

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

var p = new Person();
Run Code Online (Sandbox Code Playgroud)

您的示例obj.prepareRandomFunction();是上面的规则#2,因此this将设置为obj.

您的示例randomFunction(this.sumData.bind(this))是上面的规则#1,因此this内部randomFunction将设置为全局对象或undefined(如果处于严格模式).

由于randomFunction正在呼叫它本身使用的回调函数.bind(),则值this时它被称为将被设置为的值的回调函数内this传递给.bind()this.sumData.bind(this)经由上述规则#5. .bind()实际上创建了一个新功能,它的工作是在设置自定义值后调用原始功能this.


以下是关于该主题的其他几个参考:

如何避免"this"引用DOM元素,并引用该对象

更好地理解这一点

"this"关键字如何运作?


请注意,使用.apply()or .call()或者.bind(),您可以创建各种奇怪的东西,有时甚至是非常有用的东西,这些东西在C++之类的东西中是无法做到的.您可以使用世界上的任何函数或方法,并将其称为某种其他对象的方法.

例如,这通常用于将arguments对象中的项目副本复制到数组中:

var args = Array.prototype.slice.call(arguments, 0);
Run Code Online (Sandbox Code Playgroud)

或类似的:

var args = [].slice.call(arguments, 0);
Run Code Online (Sandbox Code Playgroud)

这将获取数组的.slice()方法并调用它,但为其提供一个arguments对象作为this指针.的arguments对象(但不是一个实际的阵列),具有使刚好足够阵列样功能.slice()的方法可以在其上操作,并且它最终使副本arguments物品进入,然后可以与真正的阵列操作直接操作上的实际阵列.这种类型的chicanery不能无所事事地完成.如果阵列.slice()方法的其他阵列方法中不存在的上依赖arguments对象,那么这招是行不通的,但是因为它仅依赖于[].length,这两者的arguments对象有,它实际工作.

因此,这个技巧可用于从任何对象"借用"方法并将它们应用于另一个对象,只要您应用它们的对象支持该方法实际使用的任何方法或属性.这不能在C++中完成,因为方法和属性在编译时是"硬绑定"的(即使C++中的虚方法绑定到在编译时建立的特定v表位置),但可以在Javascript中轻松完成,因为属性并且在运行时通过实际名称实时查找方法,因此包含正确属性和方法的任何对象都可以使用对其进行操作的任何方法.