当你传递'this'作为参数时 [英] When you pass 'this' as an argument

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

问题描述

我正在尝试了解这个,这让我有点困惑:

  var randomFunction = function(callback){
var data = 10;
回调(数据);
};

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

obj.prepareRandomFunction();

旨在将自己设置在哪里首先在代码中呈现?例如,在我的示例中,我成功地使用它来引用 obj 并将函数绑定到 obj ,但是因为这个被作为回调函数传递,所以阻止它被设置为 randomFunction (即什么停止它从字面上传递this.sumData.bind(this),以便设置为 randomFunction 从那里打来电话)?



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



已更新
我并不是一般都会问这是如何工作的(我不认为)。我很想知道为什么这个被设置为我将其定义为我的 randomFunction 调用的参数,并且而不是在 randomFunction 中调用回调的地方。我可能是错的,但如果我要用回调(数据)交换 this.sumData.bind(this) 我目前认为我会得到不同的结果。是因为 callback 是对 this.sumData.bind(this)的引用,它是在第一次定义时(以及 obj )?






我想我已经通过这个场景了解到这个在执行时设置了。当参数被调用时,它不会作为参数传递。

解决方案

函数调用中的这个根据函数的调用方式设置。 这个设置有六种主要方式。


  1. 普通函数调用:在正常函数调用中,例如 foo()设置为全局对象(在浏览器中为窗口)或未定义(在Javascript的严格模式下)。


  2. 方法调用:如果调用方法,例如 obj.foo(),然后在函数内设置为 obj


  3. .apply()或.call():如果 .apply() .call使用(),然后根据传递给 .apply() c>或 .call()。例如,您可以执行 foo.call(myObj)并将设置为 myObj 在该特定函数调用的 foo()内。


  4. 使用new:如果您使用 new 调用函数,例如 new foo() ,然后创建一个新对象,并使用调用构造函数 foo ,将此设置为新创建的对象。 / p>


  5. 使用.bind():使用 .bind() a时从该调用返回新的存根函数,该调用在内部使用 .apply()来设置传递给指针 .bind()。仅供参考,因为 .bind()可以用 .apply()实现。


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


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






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



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



了解一些回调函数也很有用(例如DOM事件处理程序)使用特定值调用此来调用,这是由调用回调函数的基础结构设置的。在内部,它们都使用 .call() .apply()所以这不是新规则,但是是值得注意的。回调函数的契约可能包括它如何设置这个的值。如果它没有明确设置这个的值,那么它将根据规则#1设置。



在ES6中,通过箭头函数调用函数,维护当前词汇值 this 。这是一个数组函数的例子,从 this 参考/功能/ Arrow_functions#Lexical_thisrel =noreferrer> MDN

  function Person(){
this.age = 0;

setInterval(()=> {
this.age ++; // | this |正确引用person对象
},1000);
}

var p = new Person();






obj的例子.prepareRandomFunction(); 是上面的规则#2所以这个将被设置为 obj



你的 randomFunction(this.sumData.bind(this))的例子是上面的规则#1所以 中的 randomFunction 将设置为全局对象或 undefined (如果是严格模式)。



由于randomFunction正在调用一个回调函数,该函数本身使用 .bind(),那么<$ c的值回调函数内的$ c> this 在被调用时将被设置为传递给这个的值.bind() this.sumData.bind(this)中,通过上面的规则#5。 .bind()实际上创建了一个新功能,它的工作是调用原始功能AFTER设置自定义值 this






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



如何避免这个引用DOM元素,并引用对象



更好地理解这一点



这个怎么样?关键字工作?






注意,使用 .apply() .call() .bind(),你可以创建各种各样的有些奇怪的事情,有时是非常有用的事情,在C ++这样的事情上永远无法做到。您可以使用世界上的任何函数或方法,并将其称为某种其他对象的方法。



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

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

或类似情况:

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

这需要数组的 .slice()方法并调用它,但为它提供一个arguments对象作为 this 指针。 参数对象(虽然不是实际数组),具有足够的类似于数组的功能, .slice()方法可以对它进行操作,最终将 arguments 项的副本复制到一个实际的数组中,然后可以直接使用实数组操作进行操作。这种类型的chicanery不能无所事事地完成。如果数组 .slice()方法依赖于 arguments 对象上不存在的其他数组方法,那么这个技巧不起作用,但因为它只依赖于 [] .length ,两者都是 arguments 对象有,它确实有用。



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


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

Is this designed to set itself where it is first rendered in code? 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)?

I'm a noob trying to learn. Thanks.

Updated 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. 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)?


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 inside a function call gets set according to how a function is called. There are six main ways that this gets set.

  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).

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

  3. .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.

  4. 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.

  5. 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().

  6. 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.

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.


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.

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.

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.

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


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

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).

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:

How to avoid "this" refering to the DOM element, and refer to the object

A better understanding of this

How does the "this" keyword work?


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.

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

or similarly:

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

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.

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天全站免登陆