foreign
who will be speaking to us about
JavaScript classes for the python
programmer over to you
[Applause]
good afternoon I'm going to be spending
a lot of time standing this way because
those lights are quite aggressive
um thank you
just a quick introduction of who I am
I've been working with python for about
25 odd years I've been working with
Django for about 16 years long enough
that they um they actually invited me
onto the core team at some point and I'm
here with many thanks to my employer who
is the reason I've had to do the
investigations that led to me coming to
the realization this content needed to
be shared
I'm going to cover a lot of the
differences and similarities between how
classes and objects work in JavaScript
versus python because that helps us all
especially those of us who work in the
web space
let's start off with some very basic
fundamentals
in Python
we have explicit classes you say class
you create name you define your class in
there it is in JavaScript it's a little
more subtle every object can be thought
of as a class
pretty much when it comes to scoping
in Python we have self and that is
explicitly passed in to your methods
it's injected for you you don't have to
remember it's just attached and this is
done I discovered a couple of years ago
using the descriptor protocol so anyone
who's familiar with at property the same
functionality in classes that lets that
work is how functions
know to inject self when they're called
as part of a class in JavaScript
it's a little different
what happens is you have it this object
which is the scope from which you were
called
if you are called via looking up another
object then that object is your this you
can actually
um
play with that and lose that if you're
not careful when passing functions
around
in Python we can actually trick python
into injecting a different this or a
different class as around and we can
call a method on another class without
this
by actually calling the cost method not
the instance method
on JavaScript they have this thing
called bind which is a method on every
function so you can say when this gets
called
I want this object that I'm passing to
you now to be my scope to be my this
next is Properties or attributes on our
objects
in Python every instance has a type
which is its class and when you look up
a property that doesn't exist on your
instance python will then go look it up
on your class
and then its parent clause
and so on and so on until we reach
object at which point we say oh you
haven't got one
in JavaScript
okay I've got my fragments out of order
here
we do we can in Python actually test if
there is a direct attribute on our class
by looking at the dunder dict of the
class to say if this name is in there
then it has that on itself it's not
inheriting it
oh
in JavaScript every object has a
prototype just one when you look up the
property it doesn't exist on your
current instance or your current object
JavaScript will go and look at the
Prototype and then they'll prototypes
prototype and so on and so on until you
reach
the null object or there's no more
prototypes to go up to so it's very
similar in way to the pythons climbing
up the tree except it's directly on your
object rather than the type of your
object
additionally in similar allergy we can
ask the object class itself and they
provide us a static method to say hey
does this object actually have its own
instance its own attribute
or is it inheriting it of from its
prototype tree
next we'll step on to Constructors
now in Python we're all familiar with
the dunder init method which is we can
Define on our class to say hey let's get
set up and let's get ready to go
in JavaScript you
you actually write a function that is
not directly part of your class which
constructs your object instance
pretty much the same way very similar as
we can see you can do the same things
you assign values to this
in Python we can create our object using
the Constructor by calling the class in
that gets called implicitly
when we do this
in JavaScript you invoke the Constructor
function and it returns you the newly
constructed object
inheritance again it's a little
different in basic objects in Python
we actually say that my new
sorry every
I've got the wrong glasses on I'm not
having trouble reading any uh
any attributes on our class are
inherited by the instance
this way that when we've put a method
there which is an attribute on a class
we can access it that way in JavaScript
objects inherit via their prototype of
their Constructor
so my class instance on the left has
inherited the Greet function from its
class
on the right the JavaScript function
is inheriting the Greek function from
the Prototype of the function we've had
actually
added it that way and so instead of when
it's constructed it inherits the object
prototype of the object it inherited it
inherits the Prototype
of the function that constructed it
static methods methods on the class
itself or on the Constructor
very similar patterns in Python we
actually have a decorator to say this is
a static method so it won't be passed a
class or an instance
and we can often use that as Factory
functions to produce new instances in
JavaScript
because it's inherited from the
Prototype of the parent or with the
Prototype itself we can attach objects
and methods and attributes directly to
the function which is an object very
much like in Python
so invoking this here we would get a
mock object from a python class
and here in JavaScript
we call it the same way it looks very
much the same we get an object back it's
just a method a function attached to the
function object which is our Constructor
a subclassing
in Python is a very explicit thing
because python explicitly supports
classes so if we just say them in my
definition of my class well it's one of
these with these changes and when I
wanted to go and say well do what the
parent class would do I call Super
in JavaScript it requires a little bit
more effort because it's a constructed
concept rather than a native part of the
language so we have to tell
our Constructor that we're creating now
that its prototype
has a prototype of the Prototype of the
parent classes Constructor and that
sounds a little bit roundabout and
actually doing that is also a little bit
roundabout so here we've defined our new
Constructor and it calls the parent
classes
Constructor using call which is similar
to to bind but it actually you pass it
the scope and then the arguments as a
list
and then we have to say can we create a
new copy of our parent classes prototype
but add to it this Constructor which is
this is a very explicit and detailed way
of saying I want to put another property
on there
very tedious
next we come to a very noticeable
difference in terminology and
functionality between Python
and JavaScript
Python's init function although we often
refer to it as a Constructor is not a
Constructor
it's the error in the name it's an
initializer and this difference means
that it's only invoked after the
instance object is actually created and
by the time that we get to the instance
and we get to our initializer all the
properties are declared on this instance
all the properties have been inherited
from the class the parent class the
parent class all the way back
and all of those attributes are visible
to even the superclasses methods once
they're called and invoked via super
so here's an example
if we have a python class called Unit
and it has a static a property called
Foo and they now initializer we get bar
and we ask for the amount and multiply
them when I create a chunk as a subclass
of that if I create unit with a two
value it's two times one we get two
chunk two times five we get 10 pretty
straightforward
if we tried the same in JavaScript and
we call new what we get what happens is
we get a blank object created
then its prototype is set to the
Constructor function's prototype
then the Constructor is called
with this new object cast as it's this
I've got my slides out of order I'm
sorry about that
next we enter
es6 or es2015 JavaScript released in
2015 which introduced a whole bunch of
things but one of the nicest things it
introduced was class syntax
this allows us to redo all those things
we've done before in a syntax that looks
a lot more like other languages classes
now we have an explicit Constructor
function we can define static methods
and static properties and inherited
functions for everybody else to use now
subclassing becomes a nice direct clean
this class extends that class my
Constructor calls the superclasses
Constructor and then does whatever it's
local Things Are
unlike Python and very much like a lot
of other languages JavaScript does not
support multiple inheritance you can go
up the chain one by one but you can't
say that this class mixes in multiple
classes
another important difference and this is
actually different from the Constructor
functions we saw earlier is that you
must con must call
your superclass Constructor before you
do any modification of your this object
if you try to do it you'll get an error
like this to say exactly that
again static properties can be declared
just like they were before very much
like it in Python now we just put it
inside the class declaration and InFocus
directly from the object itself The
Constructor rather than as a member
and prior to es6 it would have looked
very much like this so it actually
hasn't changed a lot it's very very
similar
next I want to talk about what I'm
calling subclass overrides
so their example before
where we have an object which takes a
factor a scaling Factor
and then we pass it an amount and it'll
tell us an amount comes out
and then we have a subclass of it
and it gives us a different amount
because the init function has gone off
okay I'll put that number in I'll
multiply them and out we come with our
amount
in JavaScript if we tried the same thing
looks almost identical we have our
Constructor and we have an amount it's
time to factor and how we get is a two
but if we try the subclass
um why did we get five
why did we get two
the wrong number comes out
why does the wrong number come out
part of the problem and part of the big
conceptual difference and what I was
talking about with the Constructor
versus initializer before is that
JavaScript Constructors are called in
order because you have to call your
parent Constructor before you do any
work that goes all the way back to the
root object
from the bottom all the way back up to
the top there's this layered concept and
each layer
can only see what's being defined so far
what it has attached to the construction
which means that all the methods all the
overrides all the shadowed attributes
you've got on your subclasses aren't
there yet
additionally public fields which is like
a factor one here
are added just before calling the
Constructor function
so what has happened in our example
is that factor was actually one when the
scale Constructor was was called
and therefore when it is set this dot
amount it is gone and multiplied it by
one
then
when the bigger class gets its static
attributes or it's its class members set
up before its Constructor is called
then the factor is set to five this is a
bit of a trick that catches you out
sometimes
so how can we fix this what patterns can
we follow to avoid this problem in
future
first you can use it as a static member
and then explicitly reference the
Constructor that was used to trigger
this Construction in the first place
rather than your current version of the
of the truth this way we stash the
static property on the Constructor and
then we go into reference whichever one
was there first so here's the example of
that code Rewritten we have a static
Factor instead of factor
and here in our code we see we say this
dot constructor.factor we're referring
to whichever Constructor was used during
the construction initially of this
object
so it will always be the Constructor
that was passed to new rather than the
current Constructor that we're calling
so we can actually use this layering
effect to our advantage
okay
since we know that they're going to get
called in that order and that the
object's going to exist in the
particular State as we get there
we can use a static initialized fields
um
as they're evaluated during construction
so as it's a layered thing
we can use this to provide helper
methods for next classes down to access
this is a natural thing in Python
because we already know that all those
methods are put together already but we
can do this as a deliberate effort in in
JavaScript to make things a little
easier to use
so as an example we might on our Base
Class have a setup things method
and then as a static initializer during
uh child class called that to say what
this field should be
now notably in this scope this is
referring to the object that's under
construction and super is our parent
class or the Constructor just like when
we're using Constructor function
static initializers public Fields just
like we saw with facta and the class can
have its own static initializers as well
so we've already seen a very basic case
of this with static initializers being
methods and properties that we Define on
the Constructor object itself or the
base class
but they can also be methods that
include whole code blocks with
conditional work and so on to make it
initialization of of things that do not
depend on the arguments passed into your
Constructor or may only depend on
arguments that have already been handled
by parent classes
this is a nice way to make your your
Constructor functions a little tighter a
little smaller so that they are more
focused on what the user has decided
rather than what you've decided as a
general practice
came to include here a nice practical
example
um of by using the static initializers
our Base Class can actually provide
helper functions for the other class to
set up its own static methods
here is an example of an enum class
and we say that we've got setup values
as method and then our enumclass does in
a static Constructor block that we're
going to call that method with a bunch
of values
here we can see it's simply Maps over
the values
and tries to set on this
the uppercase version of that name and
then the index back to the value and the
product of this output is that we now
have an e num very much like python
where I can look it up by name
or I can look it up by index
right and this has gone just a little
bit faster than I was hoping but there
we are undone any questions please
[Applause]
thank you
thank you Curtis
um yeah we have time for some questions
oh we have on there
oh it's a Russell
of course it's a raffle
thanks very much
um a lot of the issues or the causes of
confusion in the JavaScript class World
seem to stem from which this is this and
which one is that and so on
any tips trip tricks suggestions hints
for how to either diagnose or prevent
error when you get into that kind of
situation
so the biggest one was actually
mentioned early on
uh here we're talking about how and I I
did want to provide more detail on this
this is good
um
this when you call a function is the
scope you were called from and if you
looked up via an object as I show here x
dot Foo then in this case X
is
the scope of it is this once you're
called so if you remember to always look
up
fire function then you can control your
scope if you are passing a callback to
which is very common in in JavaScript
for a long time like we're doing down at
set timeout you have two options either
you can wrap it in a new function that
deliberately looks up your object
to get that function because if you pass
the function on Excel on its own you've
lost this the other is bind bind creates
a new function which always has in this
case X has its scope as it's this it's
bound it's fixed it's done you cannot
undo it except unless you call bind
again or or a call as I showed later on
is another option that way you can say
always I want this and you'll see this a
lot in older react code
where the Constructor of the class will
go through and grab all of its methods
and say on the instance the same name
equals that function dot bind this that
way doesn't matter if you pass them as a
callback or use them in any other way
they're always bound to the current
instance to make sure that that scope
doesn't creep away on you and disappear
do we have any other questions
foreign
struggle with context switching between
Python on the server and JavaScript on
the client does my head in
can you talk through the pros and cons
of doing that just suck it up versus
node on the server versus a python to
JavaScript transpiler oh that's an
interesting one so my personal view is
if I had the choice
I would not use JavaScript
but in the browser we currently don't
really have the choice there have been
some great examples shown at this
conference that it's it's there I would
much rather have a single language so I
definitely understand why node happened
as a thing because all the people who
already had all the familiarity and
expertise in JavaScript moved over to
the server and went well I'm going to
bring my language with me perfectly
valid choice I like the idea of going
the other direction which Russell has
helped with and various other people
have helped with in bringing python to
the browser at the moment I find your
best cleanest option is really to
understand both languages and use each
one in its field
um I have not played with any of the
transpilers but I understand that some
of them have been around a couple of
decades now
I don't feel that you're really going to
get the best performance results
if
you're just trying to shim one to look
like the other and a lot of the times
when we're working in the web the
performance can really really matter
so
there's a lot of different takes on on
how to do that
JavaScript has definitely improved a lot
over the last decade
I now find it much much closer to python
a much more cleanly defined and they are
actually in some places dropping some of
the um some of the old things that they
found very painful to deal with there's
actually a speaker's note on this slide
to talk about with
which is no longer in fact if you go to
the Mozilla developer Network they say
don't use this some browsers have even
stopped supporting it where you could
say with X call Foo and it would make X
the current this
so that's an option that is in
JavaScript but no longer there so
JavaScript is maturing and growing and
involving python is 2 and I think
JavaScript is a lot less
painful than it used to be and a lot
less scary than I used to find it
but I was hoping with this talk to get
people a little more familiar with what
you're going to stumble across when you
start trying to use it and why the
things are constructed the way they are
because it's important to recognize that
the new class structure stuff that was
there is really the old Constructors and
functions and and prototypes with a new
syntactic sugar on top
do we have any other questions
guess not
um thank you so much Curtis
um thank you
[Applause]