I have recently come across two ways of adding a method to a class in javascript ES6. Here they are in a nutshell:
class SomeClass {
someMethod(arg) {
console.log(this.anotherMethod);
// This will produce an error because 'this' is undefined here.
}
anotherMethod = (arg) => {
// does stuff
}
}
Can someone give me a good explanation of what is happening here, and the meaning of the syntax? I understand from the babel tutorial that the arrow =>
in ES6 indicates a function. But something else is going on here I think.
Specifically, if I'm not mistaken, if I were try to access someMethod()
via the this
keyword, it would not work. I think the key is in an explanation that I can't quite parse form the Babelify ES6 tutorial:
Unlike functions, arrows share the same lexical this as their surrounding code.
Does this mean that the arrow symbol will assign the function to the this of the scope surrounding it? So that if you use an arrow in the scope of a class, the function is being assigned to the object to which this points?
I ran this the sample code above through Babelify's ES6 repl. I can't quite follow the code. It looks to me as if the method created using the arrow syntax is being added to the new Class=Object itself, whereas the method created without the arrow syntax is being added to the Class=Object's prototype.
Does anyone have a good concise explanation of what the difference is, and what the code below is doing?
"use strict";
var _createClass = (function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
})();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var SomeClass = (function () {
function SomeClass() {
_classCallCheck(this, SomeClass);
this.anotherMethod = function (dog) {
// do stuff
};
}
_createClass(SomeClass, [{
key: "someMethod",
value: function someMethod(arg) {
console.log(this.anotherMethod);
// This will produce an error b/c this is undefined here.
}
}]);
return SomeClass;
})();
Your understanding and expectation of arrow functions is correct.
You are using a controversial ES7 proposal: class properties. It is basically the same as declaring that property inside the constructor:
Hence
this
would refer to the instance.If you disable experimental mode in Babel you will see that this property declaration produces a syntax error.
The difference is that one is valid and the other is a syntax error.
According to Class Definitions,
That means that a class body can only contain method definitions or static method definitions.
They are defined in Method Definitions:
Therefore, the following code is not allowed inside a class body:
If you use Traceur instead of Babel, it will complain about the syntax error.
Yes, though I'd have said "the this of the current execution context".
If I understand what you're asking correctly, the example can be simpler:
Sorry, missed:
It's a round–about way of creating a constructor. The _createClass function copies properties from the protoProps object to the constructor's prototype, and staticProps object to the constructor itself using Object.definePropety.
The constructor ("class") also has a _classCallCheck method so if, when called, its this isn't an instance of itself (i.e. it hasn't been called as a constructor), then the call fails. This is to check that it's been called with new, but it's not foolproof since this can be set in other ways (though I don't know if there's any point to that in this case).
Maybe that cuts a few corners, but it's the gist of it.