admin管理员组文章数量:1327937
I'm new to Javascript and just want to make sure I'm understanding how it handles the this
keyword, since... well, it seems like it's pretty messy. I've checked out similar questions on StackOverflow and want to make sure I'm not moving forward with the wrong idea.
So I'm defining a class like so, and want to process every point received in the constructor.
function Curve(ptList) {
this.pts = [];
if(ptList.length > 2) {
// I want to call "addPoint" for every item in ptList right here
}
}
Curve.prototype.addPoint = function(p) {
this.pts.push(p);
/* some more processing here */
}
So, initially I thought I could just do:
ptList.forEach(this.addPoint);
but I can't, because that is simply passing a pointer to the prototype function, which means this
in addPoint
refers to the global object.
Then I tried:
ptList.forEach(function(p) { this.addPoint(p); });
but I can't, because this
refers to the global scope as soon as I enter that internal function (it no longer refers to the Curve
object being constructed), so addPoint
is undefined.
The way to get around that is to make a variable that refers to this
in a scope I can still talk to in the subfunction:
var _this = this;
ptList.forEach(function(p) { _this.addPoint(p); });
And this finally works (but looks really weird to someone without JS experience). But then I found out about the bind
function, which lets me not define a trivial function wrapper:
ptList.forEach(this.addPoint.bind(this));
and it seems like, finally, this is the best and most concise way to do it, even thought it looks silly. Without the bind
function, addPoint
has no understanding of which object it was called on, and without the first this
, I can't even find my addPoint
function.
Is there a better way to do this seemingly simple thing, or is that last line of code the remended way?
I'm new to Javascript and just want to make sure I'm understanding how it handles the this
keyword, since... well, it seems like it's pretty messy. I've checked out similar questions on StackOverflow and want to make sure I'm not moving forward with the wrong idea.
So I'm defining a class like so, and want to process every point received in the constructor.
function Curve(ptList) {
this.pts = [];
if(ptList.length > 2) {
// I want to call "addPoint" for every item in ptList right here
}
}
Curve.prototype.addPoint = function(p) {
this.pts.push(p);
/* some more processing here */
}
So, initially I thought I could just do:
ptList.forEach(this.addPoint);
but I can't, because that is simply passing a pointer to the prototype function, which means this
in addPoint
refers to the global object.
Then I tried:
ptList.forEach(function(p) { this.addPoint(p); });
but I can't, because this
refers to the global scope as soon as I enter that internal function (it no longer refers to the Curve
object being constructed), so addPoint
is undefined.
The way to get around that is to make a variable that refers to this
in a scope I can still talk to in the subfunction:
var _this = this;
ptList.forEach(function(p) { _this.addPoint(p); });
And this finally works (but looks really weird to someone without JS experience). But then I found out about the bind
function, which lets me not define a trivial function wrapper:
ptList.forEach(this.addPoint.bind(this));
and it seems like, finally, this is the best and most concise way to do it, even thought it looks silly. Without the bind
function, addPoint
has no understanding of which object it was called on, and without the first this
, I can't even find my addPoint
function.
Is there a better way to do this seemingly simple thing, or is that last line of code the remended way?
Share Improve this question asked Jan 22, 2015 at 0:06 XenoScholarXenoScholar 1873 silver badges10 bronze badges 4- 1 For plete illumination on this in Javascript, check out this free book: github./getify/You-Dont-Know-JS/tree/master/… It will answer all of your questions. – Tad Donaghe Commented Jan 22, 2015 at 0:09
-
3
This question is asked at least once a day. The solution is really understanding how
this
works, then you'll have an aha moment and realize why it is not silly. But there's another way.forEach(this.addPoint, this)
– elclanrs Commented Jan 22, 2015 at 0:09 -
Depends on your viewpoint. For instance, in knockoutjs it's a mon idiom to capture a copy of
this
with the linevar self=this
. Lately,.bind
is more monplace. – spender Commented Jan 22, 2015 at 0:10 -
If
forEach
did not provide the convenience then yes, one of your solutions would be the way to go. – Jon Commented Jan 22, 2015 at 0:10
1 Answer
Reset to default 8The forEach()
method and other similar array methods like map()
and filter()
provide an optional parameter called thisArg
specifically for this purpose.
This serves as the this
"argument" that is provided to the function when it is called:
ptList.forEach(this.addPoint, this);
When such a parameter isn't available, then choosing between using a closure variable (the variable name self
is often used for this) or .bind()
is mostly a matter of preference. Note that another option is to define functions inside your constructor and capture everything in a closure:
function Curve(ptList) {
var pts = [];
function addPoint(p) {
pts.push(p);
}
if(ptList.length > 2) {
ptList.forEach(addPoint);
}
this.addPoint = addPoint;
}
This requires a bit more memory than putting the functions on a prototype since every instance gets its own copy (and also rules out some of the things a prototype allows you to do), but Douglas Crockford (the inventor of JSON and JSLint) recently said that he doesn't even use this
anymore, with the rationale that memory is cheap, but CPU cycles are not (traversing the prototype chain requires a fair amount of processing).
本文标签: Calling a class function in forEach how Javascript handles quotthisquot keywordStack Overflow
版权声明:本文标题:Calling a class function in forEach: how Javascript handles "this" keyword - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742253920a2441273.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论