当您通过"this"作为参数时? [英] When you pass 'this' as an argument?

查看:46
本文介绍了当您通过"this"作为参数时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习this,这使我有些困惑:

I'm trying to learn about this, and it's confusing me a bit here:

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();

this是否旨在将自身设置为在代码中首次呈现的位置?

Is this designed to set itself where it is first rendered in code?

例如,在我的示例中,我成功地使用它来引用obj并将该函数绑定到obj,但是由于this作为回调函数传递,因此阻止了它的产生设置为randomFunction(即是什么阻止它从字面上传递"this.sumData.bind(this)",以便从该位置调用this时将其设置为randomFunction)?

For instance, in my example I'm successfully using it to refer to obj and also binding the function to obj, but since this is being passed as a callback function, what is stopping it from being set as randomFunction (i.e. what's stopping it from literally passing "this.sumData.bind(this)" so that this is set to randomFunction when it gets called from there)?

我并没有确切询问这通常如何工作(我不认为).我主要是想知道为什么在我将其定义为randomFunction调用的参数的地方设置this的原因,而不是为什么在randomFunction内调用callback的地方设置了它.

I'm not exactly asking how this works generally (I don't think). I'm mainly curious to know why this gets set where I define it as the argument of my randomFunction call, and not where callback gets called within randomFunction.

我可能是错的,但是如果我将this.sumData.bind(this)换成我现在拥有的callback(data),我想我会得到不同的结果.

I could be wrong, but if I were to swap this.sumData.bind(this) with the callback(data) that I currently have I think I would get a different result. Is that because callback is a reference to this.sumData.bind(this) when it was first defined (and where this is obj)?

我想我已经从这种情况中学到了this在执行时已设置.不会在以后调用该参数时将其作为参数传递.

I think I've learned through this scenario that this is set when it's executed. It's not passed as a argument to be set later when the argument is called down the line.

推荐答案

this.设置this的主要方法有六种.

this inside a function call gets set according to how a function is called. There are six main ways that this gets set.

  1. 常规函数调用:在诸如foo()之类的常规函数​​调用中,将this设置为全局对象(在浏览器中为window)或undefined(在JavaScript的严格模式下).

  1. Normal Function Call: In a normal function call such as foo(), this is set to either the global object (which is window in a browser) or to undefined (in JavaScript's strict mode).

方法调用::如果调用了诸如obj.foo()之类的方法,则在函数内部将this设置为obj.

Method Call: If a method is called such as obj.foo(), then this is set to obj inside the function.

.apply()或.call()::如果使用.apply().call(),则根据传递给.apply()的内容设置this.call().例如,您可以执行foo.call(myObj)并将该特定函数调用的this设置为foo()内的myObj.

.apply() or .call(): If .apply() or .call() is used, then this is set according to what is passed to .apply() or .call(). For example, you could do foo.call(myObj) and cause this to be set to myObj inside of foo() for that particular function call.

使用新功能:如果使用new调用函数,例如new foo(),则会创建一个新对象,并使用this调用构造函数foo设置为新创建的对象.

Using new: If you call a function with new such as new foo(), then a new object is created and the constructor function foo is called with this set to the newly created object.

使用.bind()::当使用.bind()时,该调用返回一个新的存根函数,该函数内部使用.apply()设置传递给的this指针.bind().仅供参考,这实际上没有什么不同,因为.bind()可以用.apply()实现.

Using .bind(): When using .bind() a new stub function is returned from that call that internally uses .apply() to set the this pointer as was passed to .bind(). FYI, this isn't really a different case because .bind() can be implemented with .apply().

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

Using ES6 Fat Arrow Function Defining a function via the arrow syntax in ES6+ will bind the current lexical value of this to it. So, no matter how the function is called elsewhere, the this value will be set by the interpreter to the value that this has when the function was defined. This is completely different than all other function calls.

通过回调函数可以找到第七种方法,但这并不是它自己的方案,而是调用回调的函数使用上述方案之一,它确定了什么this的值将在调用回调时出现.您必须查阅调用函数的文档或代码,或者自己进行测试,以确定在回调中将this设置为什么.

There's sort of a seventh method, via a callback function, but it isn't really its own scheme, but rather the function calling the callback uses one of the above schemes and that determines what the value of this will be when the callback is called. You have to consult either the documentation or the code for the calling function or test it yourself to determine what this will be set to in a callback.

在JavaScript中要理解的重要一点是,JavaScript中的每个单个函数或方法调用都会为this设置一个新值.而且,设置哪个值取决于函数的调用方式.

What is important to understand in JavaScript is that every single function or method call in JavaScript sets a new value for this. And, which value is set is determined by how the function is called.

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

So, if you pass a method as a plain callback, that method will not, by default, get called as obj.method() and thus will not have the right value of this set for it. You can use .bind() to work around that issue.

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

It's also useful to know that some callback functions (such as DOM event handlers) are called with a specific value of this as set by the infrastructure that calls the callback function. Internally, they all use .call() or .apply() so this isn't a new rule, but is something to be aware of. The "contract" for a callback function may include how it sets the value of this. If it does not explicitly set the value of this, then it will be set according to rule #1.

在ES6中,通过箭头函数调用函数,将保持当前词法值this.这是维护词法this

In ES6, calling a function via an arrow function, maintains the current lexical value of this. Here's an example of the array function maintaining the lexical this from MDN:

function Person(){
  this.age = 0;

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

var p = new Person();


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


Your example of obj.prepareRandomFunction(); is rule #2 above so this will be set to obj.

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

Your example of randomFunction(this.sumData.bind(this)) is rule #1 above so this inside of randomFunction will be set to the global object or undefined (if in strict mode).

由于randomFunction正在调用本身使用.bind()的回调函数,因此在调用函数时,this的值将被设置为传递给.bind()this的值. this.sumData.bind(this),如上面的规则5所述. .bind()实际上创建了一个新函数,即在将自定义值设置为this之后调用原始函数.

Since randomFunction is calling a callback function which itself used .bind(), then the value of this inside the callback function when it is called will be set to the value of this that was passed to .bind() in this.sumData.bind(this) as via rule #5 above. .bind() actually creates a new function who's job it is to call the original function AFTER setting a custom value of this.

以下是该主题的其他两个参考文献:

Here are a couple other references on the topic:

对此有更好的理解

"this"如何关键字工作?

请注意,通过使用.apply().call().bind(),您可以创建各种有点奇怪的东西,有时还可以创建某些非常有用的东西,而这些东西在

Note, that with the use of .apply() or .call() or .bind(), you can create all sorts of somewhat odd things and sometimes quite useful things that could never be done in something like C++. You can take any function or method in the world and call it as if it were a method of some other object.

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

For example, this is often used to make a copy of the items in the arguments object into an array:

var args = Array.prototype.slice.call(arguments, 0);

或类似地:

var args = [].slice.call(arguments, 0);

这将使用数组的.slice()方法并对其进行调用,但为它提供一个参数对象作为this指针. arguments对象(虽然不是实际的数组)具有足够的类似于数组的功能,.slice()方法可以对其进行操作,并且最终将arguments项的副本复制到实际的数组中,然后可以可以直接通过实数数组操作进行操作.这种骗人的行为是不会故意的.如果数组.slice()方法依赖于arguments对象上不存在的其他数组方法,则此技巧将不起作用,但由于它仅依赖于[].length,而这两个都依赖于arguments >对象具有,它确实可以工作.

This takes the array's .slice() method and calls it, but supplies it with an arguments object as the this pointer. The arguments object (though not an actual array), has just enough array-like functionality that the .slice() method can operate on it and it ends up making a copy of the arguments items into an actual array which can then be operated on directly with real array operations. This type of chicanery can't be done willy-nilly. If the array .slice() method relied on other array methods that are not present on the arguments object, then this trick would not work, but since it only relies on [] and .length, both of which the arguments object has, it does actually work.

因此,该技巧可用于借用"交易.方法,只要您将它们应用到的对象支持该方法实际使用的任何方法或属性,就可以将它们应用到另一个对象.这在C ++中无法完成,因为方法和属性是硬绑定"的.在编译时(甚至C ++中的虚方法都绑定到在编译时建立的特定v表位置),但是可以轻松地在JavaScript中完成,因为属性和方法是在运行时通过其实际名称实时查找的,因此包含正确的属性和方法将与在这些属性和方法上运行的任何方法一起使用.

So, this trick can be used to "borrow" methods from any object and apply them to another object as long as the object you are applying them to supports whatever methods or properties that the method actually uses. This can't be done in C++ because methods and properties are "hard bound" at compile time (even virtual methods in C++ are bound to a specific v-table location established at compile time), but can be easily done in JavaScript because properties and methods are looked up live at runtime via their actual name so any object that contains the right properties and methods will work with any method that operates on those.

这篇关于当您通过"this"作为参数时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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