3 ms·
So, this is really interesting... JavaScript is forced to make the pessimal choice of only ever having dynamic-bound "this", because of that favorite whipping
by jashkenas 15y ago
So, this is really interesting...
JavaScript is forced to make the pessimal choice of only ever having dynamic-bound "this", because of that favorite whipping boy ... prototypal inheritance.
If JavaScript had a notion of a class (even as a constructor function + prototype) definition, then it would be possible to tag methods with the correct instance reference, as in Ruby and in Python. Unfortunately, because the standard pattern for defining an instance method is:
Klass.prototype.method = function() {
...
};
... where the function is an expression just like any other, you have to have dynamic-bound this to make prototypes work correctly by default.
- jballanc 15y agoYou should look at Lua. Yes, if you want a notion of "self" or "this" with prototypal inheritance, then it must be dynamically bound. However, this does not have to be a burden on, or even be noticeable by, the programmer. Good language design can avoid most of the pitfalls in JavaScript...
- extension 15y agoTo elaborate, Lua has special syntax for defining and calling methods vs unbound functions. In Lua, function woot:donk() ... end woot:donk() is equivalent to woot.donk = function(self) ... end woot.donk(woot) and when you define a function normally e.g. function() ... end there is no self parameter, thus the one from the parent scope is captured. The flaw with JS, really, is that it forces every function to be a method, and doesn't let you express whether you are defining one or the other. (think I got this right, my Lua is a bit rusty)
- LeafStorm 15y agoYep, that's pretty much it. And the woot:donk() notation will only evaluate what's left of the colon once, which is nice.
- judofyr 15y agoThis isn't really about prototypal inheritance. If you wrote methods like this in Ruby, you would have the same issue: Klass.method := lambda { p self } Also, if JavaScript looked like this, you wouldn't need the fat arrow: // Let's call this a "prototype function" Klass.prototype.function method() { … } Together with these rules: * A function always captures its outer `this` * The getter of a prototype function (`thing.method`) always returns a binded function (where `this` == `thing`).
- jashkenas 15y agoAbsolutely. I don't mean that dynamic "this" is required by prototypal inheritance in general -- I mean that it's required because of JavaScript's particular implementation of prototypes, where they're exposed to you as a value, but there's no syntax where the language can tell that you're in the process of building one out.
- masklinn 15y ago> JavaScript is forced to make the pessimal choice of only ever having dynamic-bound "this", because of that favorite whipping boy ... prototypal inheritance. I don't think that's true: functions accessed via objects could very well be bound to the object (that's what Python does, accessing a method via an object instance returns a "bound method" which is curried with the instance, whereas accessing the same method via the class returns an "unbound method" which requires a class instance as its first argument).
- jashkenas 15y agoThat works in Python, because Python has a distinction between an "instance" object, and, say, a Dict. In JavaScript an object is an object is an object -- under your proposed change, what would be the value of "this, in this: Klass.prototype.method = options.method;
- masklinn 15y ago> That works in Python, because Python has a distinction between an "instance" object, and, say, a Dict. Not really, it's trivial to create a dict-like object which allows access to keys as properties, just override `__getattr__`. > In JavaScript an object is an object is an object No, objects can have a non-null [[prototype]] indicating it was created from using `new` on a constructor. > Klass.prototype.method = options.method; Depends what `options` is.