ES6 Classes with Inheritance issue and Traceur Not Showing Compiled Code - javascript

I am experimenting with ES6. In particular, classes and inheritance. In class Apple, it extends Polygon. I want to extend Polygon's method sayName() and have it go to console.log.
When I run it through traceur, I get undefined for console.log(foo);
class Polygon {
constructor(height, width) { //class constructor
this.name = 'Polygon';
this.height = height;
this.width = width;
}
sayName() { //class method
return 'Hi, I am a', this.name + '.';
}
}
class Apple extends Polygon {
constructor(length) {
super(length, length); //call the parent method with super
this.name = 'apple';
}
sayName() {
var foo = super();
console.log(foo);
}
}
let d = new Apple(5);
d.sayName();
Traceur:
System.register("class", [], function() {
"use strict";
var __moduleName = "class";
function require(path) {
return $traceurRuntime.require("class", path);
}
var Polygon = function Polygon(height, width) {
this.name = 'Polygon';
this.height = height;
this.width = width;
};
($traceurRuntime.createClass)(Polygon, {sayName: function() {
return 'Hi, I am a', this.name + '.';
}}, {});
var Apple = function Apple(length) {
$traceurRuntime.superConstructor($Apple).call(this, length, length);
this.name = 'apple';
};
var $Apple = Apple;
($traceurRuntime.createClass)(Apple, {sayName: function() {
var foo = $traceurRuntime.superConstructor($Apple).call(this);
console.log(foo);
}}, {}, Polygon);
var d = new Apple(5);
d.sayName();
return {};
});
System.get("class" + '');
How can I super sayName() in Apple class and make the console.log(foo) show the value?
I thought traceur would show me the compiled code, but it is not really. For instance, $traceurRuntime.createClass() isn't helping me see how it is creating these constructors. Am I using traceur incorrectly to view the compiled code?

super refers to the class/constructor, not to the method from which it is called. Therefore, if you want to call the parent function from within sayName(), you will have to write it like this:
sayName() {
var foo = super.sayName();
console.log(foo);
}

Related

Dynamically extending a class in javascript

How can we dynamically/programmatically extend a javascript class?
More concretely, given something like
class Polygon {
constructor(area, sides) {
this.area = area;
this.sides = sides;
}
}
const Rectangle = extend(Polygon, (length, width) => {
super(length * width, 4);
this.length = length;
this.width = width;
});
how can we implement something like extend such that it behaves the same as
class Rectangle extends Polygon {
constructor(length, width) {
super(length * width, 4);
this.length = length;
this.width = width;
}
}
?
There are three problems here:
(1) super is only available inside object methods, so there is no way to access super in an arrow function. That needs to be somehow replaced by a regular function call.
(2) Classes can only be constructed, not called (unlike functions acting as constructors). Therefore you cannot just .call the classes constructor onto the "subclass" instance. You have to create an instance of the superclass and copy that into the subclass, eventually loosing getters / setters.
(3) Arrow functions have a lexical this, so you cannot access the instance with this inside an arrow function.
Given these three problems, a viable alternative would be:
function extend(superclass, constructor) {
function Extended(...args) {
const _super = (...args) => Object.assign(this, new superclass(...args));
constructor.call(this, _super, ...args);
}
Object.setPrototypeOf(Extended, superclass);
Object.setPrototypeOf(Extended.prototype, superclass.prototype);
return Extended;
}
const Rectangle = extend(Polygon, function(_super, length, width) {
_super(/*...*/);
/*...*/
});
But honestly ... what's wrong with the native class ... extends ?
After some hacking around, I've found that this horrifyingly works.
function extend(superclass, construct) {
return class extends superclass {
constructor(...args) {
let _super = (...args2) => {
super(...args2)
return this;
};
construct(_super, ...args);
}
};
}
const Rectangle = extend(Polygon, function(_super, length, width) {
let _this = _super(length * width, 4);
_this.length = length;
_this.width = width;
});
class A {
m () {
console.log('A')
}
}
class B extends A {
m () {
console.log('B')
}
}
var a = new A()
var b = new B()
a.m()
b.m()
const MixinClass = superclass =>
class extends superclass {
m () {
console.log('extended')
}
}
const extendsAnyClass = AnyClass =>
class MyMixinClass extends MixinClass(AnyClass) {}
var AA = extendsAnyClass(A)
var BB = extendsAnyClass(B)
var aa = new AA()
var bb = new BB()
aa.m()
bb.m()
This worked for me:
const extend = SuperClass => class E extends SuperClass {
constructor() {
super('E')
}
}
class A {
constructor(arg) {
console.log('Hello from ' + arg)
}
}
class B {
constructor(arg) {
console.log('Hi from ' + arg)
}
}
const C = extend(A)
const D = extend(B)
new C() // Hello from E
new D() // Hi from E
This will dynamically extend E for any given parent class
https://jsfiddle.net/1s0op2ng/

Nested classes in AdWords Script (JavaScript) - access parent properties [duplicate]

How do you access the this object from another object instance?
var containerObj = {
Person: function(name){
this.name = name;
}
}
containerObj.Person.prototype.Bag = function(color){
this.color = color;
}
containerObj.Person.prototype.Bag.getOwnerName(){
return name; //I would like to access the name property of this instance of Person
}
var me = new Person("Asif");
var myBag = new me.Bag("black");
myBag.getOwnerName()// Want the method to return Asif
Don't put the constructor on the prototype of another class. Use a factory pattern:
function Person(name) {
this.name = name;
}
Person.prototype.makeBag = function(color) {
return new Bag(color, this);
};
function Bag(color, owner) {
this.color = color;
this.owner = owner;
}
Bag.prototype.getOwnerName = function() {
return this.owner.name;
};
var me = new Person("Asif");
var myBag = me.makeBag("black");
myBag.getOwnerName() // "Asif"
Related patterns to deal with this problem: Prototype for private sub-methods, Javascript - Is it a bad idea to use function constructors within closures?

how to write oop javascript (with inheritance) in JetBrains Webstorm/PHPStorm to get autocompletion/intellisense

Can someone write an example, of OOP JS code, i assume with annotations, where JetBrains IDEs can recognize inheritance?
e.g.
class Animal:
prop: weight
method: run()
class Cat extends Animal:
prop: name
method: eat()
so i want that Webstorm/PHPStorm autocompletes and shows info (ctrl+q) for such things:
Cat.prototype.eat= function(){
this.weight; //should be recognized as inherited property
}
var cat = new Cat();
cat.run(); //should be recognized as inherited method
What is the best way?
the following will work without any annotations:
var Animal = function () {
this.weight = 0;
this.run = function () {
}
return this;
};
var Cat = function () {
this.name = "Tom";
this.eat = function () {
return "Nyam"
}
return this;
}
Cat.prototype = new Animal();
var cat = new Cat();
cat.run()
this way also works:
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
Plus, you can use JSDoc here - see http://usejsdoc.org/tags-augments.html, for example

JavaScript inheritance: member functions not inheriting?

This is driving me crazy. I'm about to break down and cry.
Here's my code that is NOT working:
// parent class: Shirt
var Shirt = function() {
this.basePrice = 1;
}
Shirt.prototype.getPrice = function(){return this.basePrice};
Shirt.prototype.display = function(){
$('ul#products').append('<li>Product: $' + this.getPrice() + '.00</li>');
};
// subclass: ExpensiveShirt inherits from Shirt
var ExpensiveShirt = function() {
this.basePrice = 5;
};
ExpensiveShirt.prototype = Object.create(Shirt);
// make some objects and test them
var s = new Shirt();
s.display(); // this works
console.log(s.getPrice()); // this works
var e = new ExpensiveShirt();
e.display(); // this does not work!
console.log(e.getPrice()); // does not work
HERE IS THE JSFIDDLE
Now, if I add these lines, then it works:
ExpensiveShirt.prototype.getPrice = Shirt.prototype.getPrice;
ExpensiveShirt.prototype.display = Shirt.prototype.display;
But according to this I shouldn't have to: JavaScript inheritance with Object.create()?
And I really don't want to because that is bad programming. >:(
Object.create expects the prototype for the new object as its argument, not the constructor. Change your line to this, and it will work:
ExpensiveShirt.prototype = Object.create(Shirt.prototype);
As #Paulpro mentions, you need to use Object.create on Shirt.prototype and not Shirt for inheritance to work.
I usually use the following two functions to make my life easier when dealing with inheritance in JavaScript:
var Shirt = defclass({
constructor: function () {
this.basePrice = 1;
},
getPrice: function () {
return this.basePrice;
},
display: function () {
alert("Product: $" + this.getPrice() + ".00");
}
});
var ExpensiveShirt = extend(Shirt, {
constructor: function () {
this.basePrice = 5;
}
});
var s = new Shirt;
var e = new ExpensiveShirt;
s.display();
e.display();
console.log(s.getPrice());
console.log(e.getPrice());
<script>
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, properties) {
var prototype = Object.create(constructor.prototype);
for (var key in properties) prototype[key] = properties[key];
return defclass(prototype);
}
</script>
Hope that helps.

Javascript: Achieving private variables via return anonymous object

This sample achieves private variables of rectangle. The variables myLength and myWidth are different for different instances. So why is this not recommended approach?
var rectangle = function() {
var myLength = 8;
var myWidth = 6;
var getMyLength = function () {
return myLength;
};
var setMyLength = function (value) {
myLength = value;
};
var getMyWidth = function () {
return myWidth;
};
var setMyWidth = function (value) {
myWidth = value;
};
var drawFigure = function() {
console.log("Draw invoked for figure: " +
getMyLength() + " * " + getMyWidth());
};
return {
getMyLength: getMyLength,
setMyLength: setMyLength,
getMyWidth: getMyWidth,
setMyWidth: setMyWidth,
drawFigure: drawFigure
}
};
Then we use it as follows:
var myRectangle = new rectangle();
myRectangle.drawFigure(); // Draw invoked for figure: 8 * 6
myRectangle.setMyLength(3);
myRectangle.setMyWidth(5);
myRectangle.drawFigure(); // Draw invoked for figure: 3 * 5
var myRectangle1 = new rectangle();
myRectangle1.drawFigure(); // Draw invoked for figure: 8 * 6
In my opinion private variables are overrated. Do you really need to hide things from the programmer? No. Even if you made all your private variables public what difference would it make? In fact I advocate making everything public because:
It would make debugging easier. If you console.log an object then you can inspect its public properties which makes debugging easier because you can see the state of the object.
You don't need to create unnecessary closures. If you want a private variable and also want it to be accessible by a public method then you have to create a closure (one for each instance). If you make your properties public then you don't need closures. You can put the methods on the prototype. Hence you'll only have one method per class, shared by all the instances.
You don't need to create unnecessary getters and setters. What's the point of making a variable private and then allowing anybody to modify it using getter and setter functions? You might as well make the variable public.
Getters and setters, in my humble opinion, are only useful for phantom properties:
var Person = defclass({
constructor: function (firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
},
getFullName: function () {
return this.firstName + " " + this.lastName;
},
setFullName: function (fullName) {
var name = fullName.split(" ");
this.firstName = name[0];
this.lastName = name[1];
}
});
Hence in my opinion you should have written your Rectangle class as follows:
var Rectangle = defclass({
constructor: function (width, height) {
this.width = width;
this.height = height;
}
});
We then use it as follows:
var rectA = new Rectangle(8, 6);
console.log(rectA); // { width: 8, height: 6 }
rectA.width = 3;
rectA.height = 5;
console.log(rectA); // { width: 3, height: 5 }
var rectB = new Rectangle(8, 6);
console.log(rectB); // { width: 8, height: 6 }
Finally, the definition of defclass:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
So that's just my two cents on the way you should create objects in JavaScript.

Categories