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 <pyt...@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.
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to