The right way to 'call' a class attribute inside the same class
Erik
python at lucidity.plus.com
Sun Dec 18 17:52:09 EST 2016
NOTE: If you found this message by searching for help on how Python
works, be aware that it's discussing how JavaScript works, not Python!
Look elsewhere :)
Chris, this isn't directed at you (I think you get it) - just following
up with some detail for anyone who might discover this sub-thread when
searching in future.
On 18/12/16 01:21, Chris Angelico wrote:
> On Sun, Dec 18, 2016 at 12:01 PM, Erik <python at lucidity.plus.com> wrote:
>> I wish I could find the resource I originally learned this stuff from,
>> because it's quite enlightening and I'd like to link to it here
> Sounds like how Michael Schwern introduces his "Git for Ages 4 and Up"
> talk
Just in case anyone is remotely interested, I've found a reasonable link
(but it's not the one I was looking for).
I realise this is off-topic for a Python list, but it has come up
because of a Python question so I thought why not ... (I wish someone
had explained this to me in roughly-Python terms when I first had to
deal with JS ;)).
In short, AIUI, all JS functions have an implicit initial parameter
which is named 'this'. What that parameter is bound to depends on the
context of the call to that function object. In Python the callable is
of a particular type (method, function, generator) but on JS (for the
purposes of this discussion (pun intended ;)) they are all equal and
it's the calling context that determines what happens.
A JS function, whether declared with "function Foo(a, b, c) {}" or as an
expression "function (a, b, c) {}" has an implicit initial parameter
which is bound to the variable 'this' (so they are really "function
Foo(this, a, b, c) {}", "function (this, a, b, c) {}").
The value of that initial first parameter is determined by how they are
called. There are three main ways:
1) Method call:
"obj.foo(1, 2, 3)" is syntactic sugar for "obj.foo(obj, 1, 2, 3)".
2) Function call:
"foo(1, 2, 3)" is syntactic sugar for "foo(GLOBAL_OBJECT, 1, 2, 3)"
where "GLOBAL_OBJECT" is whatever the execution environment defines as
being the global object. In a browser, I think it's "window", in the JS
strict mode, I think it's "undefined" (i.e., no object), in Node.js I
think it might be something else entirely.
3) Constructor call:
"new foo(1, 2, 3)" is syntactic sugar for "foo(NEWOBJ, 1, 2, 3)"
where NEWOBJ is a newly allocated, empty object.
The other way of invoking a function object is via its "call" method
where the initial 'this' parameter can be explicitly given -
"foo.call(SPAM, 1, 2, 3)" - which is how to implement bound methods and
that sort of thing.
The main area of confusion seems to be when passing function expressions
(closures) as a callback to another function:
function Foo() {
ham(this.a, this.b, function (x) { this.frobnicate(x); });
}
Let's assume this is called with "obj.Foo();". In the function itself,
'this', is bound to 'obj'. However, in the body of the (anonymous)
function expression/closure (which sort of looks to be at the same scope
as everything else) 'this' is bound according to the rules above being
applied to at the point it is called - the object it is bound to almost
certainly doesn't have the "frobnicate" method expected.
This is why the following works:
function Foo() {
_this = this;
ham(this.a, this.b, function (x) { _this.frobnicate(x); });
}
The closure now knows how to address the 'this' object for the original
method even though it is called later by whatever 'ham()' does. Using a
bound function as the callback works in the same way.
Anyway, off-topic as I said, but if it helps other Pythoneers get to
grips with some of the weird JS semantics, it's all good :)
The link I *did* find (which probably has a bit more depth) is:
https://rainsoft.io/gentle-explanation-of-this-in-javascript/
Cheers, E.
More information about the Python-list
mailing list