当您通过"this"作为参数时? [英] When you pass 'this' as an argument?
问题描述
我正在尝试学习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.
-
常规函数调用:在诸如
foo()
之类的常规函数调用中,将this
设置为全局对象(在浏览器中为window
)或undefined
(在JavaScript的严格模式下).
Normal Function Call: In a normal function call such as
foo()
,this
is set to either the global object (which iswindow
in a browser) or toundefined
(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:
请注意,通过使用.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屋!