I am learning about classes in Typescript and extend. Once I compiled .ts file and looked into .js. The code for class and extend in js is quite different. In .js class is made with function not with class.
My TS code
class User4 {
private city: string = "xyx";
protected number: number = 123123;
constructor(public name: string) {}
}
class additional extends User4 {
method1() {
console.log(this.number);
}
}
export {};
While the code in **.js ** is
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var User4 = /** #class */ (function () {
function User4(name) {
this.name = name;
this.city = "xyx";
this.number = 123123;
}
return User4;
}());
var additional = /** #class */ (function (_super) {
__extends(additional, _super);
function additional() {
return _super !== null && _super.apply(this, arguments) || this;
}
additional.prototype.method1 = function () {
console.log(this.number);
};
return additional;
}(User4));
I am wondering, if there is any issue with my system or its something else because the code in .js file is really crazy
JavaScript doesn't have real classes. Classes in JS are syntax sugar, take a look at this article: How Classes work in JavaScript
You're getting this "crazy" code, because the transpiler is by default set to handle old versions of JavaScript, before class was even added as part of the language.
Related
I have 2 files (FPDevice.js and FPComponent.js). Each file with an object. I need to call a function from one file (Object) to the other file (Object).
It is working but not as expected using FPComponent.prototype.onSysexEvent.call(FPComponent); on file FPDevice.js file. I was expecting that by using FPComponent, instead of this in the context argument, that the function would inherit the properties of the FPComponent object and be able to use this.channels.
When FPComponent.prototype.onSysexEvent.call(FPComponent); function is called from the FPMidiDevice.prototype.onSysexEvent function, the call works but the inheritance is not working.
I get an error - this.channels is undefined
Since this.channels is a property of the FPComponent object, I need the inheritance of call FPComponent.prototype.onSysexEvent.call(FPComponent) to be from the FPComponent object so I can use the this.channels property within the FPComponent.prototype.onSysexEvent.
The outcome I am looking for is to have Function FPComponent.prototype.onSysexEvent inherit the properties from FPComponent object once it is called from the FPMidiDevice.prototype.onSysexEvent function.
FPDevice.js
//FPDevice.js
var __extends = (this && this.__extends) || (function ()
{
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
include_file("resource://com.presonus.musicdevices/sdk/controlsurfacecomponent.js");
include_file("resource://com.presonus.musicdevices/sdk/controlsurfacedevice.js");
include_file("FPComponent.js");
var FPMidiDevice = (function (_super)
{
__extends(FPMidiDevice, _super);
function FPMidiDevice(faderCount, sysexHeader)
{
var _this = _super.call(this) || this;
_this.faderCount = faderCount;
_this.sysexHeader = sysexHeader;
_this.lastActiveSensing = 0;
_this.activeSensingInterval = 2500;
return _this;
}
FPMidiDevice.prototype.onInit = function (hostDevice)
{
_super.prototype.onInit.call(this, hostDevice);
this.meters = [];
};
FPMidiDevice.prototype.onSysexEvent = function (data, length)
{
//########################################################################################################## //##########################################################################################################
// I am trying to use call but using FPComponent object so the call can inherit the properties from FPComponent
FPComponent.prototype.onSysexEvent.call(FPComponent);
};
return FPMidiDevice;
}(PreSonus.ControlSurfaceDevice));
function createFP16DeviceInstance()
{
return new FPMidiDevice(16, FP.Support.kSysexHeaderFP16);
}
FPComponent.js
//FPComponent.js
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
include_file("resource://com.presonus.musicdevices/sdk/controlsurfacecomponent.js");
include_file("resource://com.presonus.musicdevices/sdk/controlsurfacedevice.js");
var FPComponent = (function (_super)
{
__extends(FPComponent, _super);
function FPComponent(faderCount)
{
var _this = _super.call(this) || this;
_this.faderCount = faderCount;
_this.pagingStatusIndex = faderCount - 1;
_this.channels = [];
return _this;
}
FPComponent.prototype.onInit = function (hostComponent)
{
PreSonus.ControlSurfaceComponent.prototype.onInit.call(this, hostComponent);
this.model = hostComponent.model;
this.root = this.model.root;
this.mixerMapping = this.root.find("MixerMapping");
this.channelBankElement = this.mixerMapping.find("ChannelBankElement");
var paramList = hostComponent.paramList;
for (var i = 0; i < this.faderCount; i++)
{
var channel = new ChannelStrip;
channel.channelElement = this.channelBankElement.getElement(i);
channel.textValue = paramList.addAlias("textValue" + i);
channel.panValue = paramList.addAlias("panValue" + i);
channel.muteValue = paramList.addAlias("muteValue" + i);
channel.soloValue = paramList.addAlias("soloValue" + i);
channel.recordValue = paramList.addAlias("recordValue" + i);
channel.monitorValue = paramList.addAlias("monitorValue" + i);
channel.colorValue = paramList.addAlias("colorValue" + i);
this.channels.push(channel);
}
};
//########################################################################################################
// it is not working properly when called from FPMidiDevice.prototype.onSysexEvent on file FPMidiDevice.js
// error = this.channels is undefined
FPComponent.prototype.onSysexEvent = function ()
{
var channelIndex = 0;
var channel = this.channels[channelIndex];
channel.faderValue.value = 1;
};
return FPComponent;
}(PreSonus.ControlSurfaceComponent));
I want to convert an instance class to plain object, without losing methods and/or inherited properties. So for example:
class Human {
height: number;
weight: number;
constructor() {
this.height = 180;
this.weight = 180;
}
getWeight() { return this.weight; }
// I want this function to convert the child instance
// accordingly
toJSON() {
// ???
return {};
}
}
class Person extends Human {
public name: string;
constructor() {
super();
this.name = 'Doe';
}
public getName() {
return this.name;
}
}
class PersonWorker extends Person {
constructor() {
super();
}
public report() {
console.log('I am Working');
}
public test() {
console.log('something');
}
}
let p = new PersonWorker;
let jsoned = p.toJSON();
jsoned should look like this:
{
// from Human class
height: 180,
weight: 180,
// when called should return this object's value of weight property
getWeight: function() {return this.weight},
// from Person class
name: 'Doe'
getName(): function() {return this.name},
// and from PersonWorker class
report: function() { console.log('I am Working'); },
test: function() { console.log('something'); }
}
Is this possible to achieve, and if so, how?
In case you're wondering, I need this because I am using a framework that, unfortunately, accepts as input only an object, whereas I am trying to use TypeScript and class inheritance.
Also, I am doing the above conversion once so performance isn't an issue to consider.
The solutions consisting of iterating through object properties will not work if the compiler's target option is set to es6. On es5, the existing implementations by iterating through object properties (using Object.keys(instance)) will work.
So far, I have this implementation:
toJSON(proto?: any) {
// ???
let jsoned: any = {};
let toConvert = <any>proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(this);
return;
}
jsoned[prop] = val;
const proto = Object.getPrototypeOf(toConvert);
if (proto !== null) {
Object.keys(this.toJSON(proto)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON') return;
if (typeof proto[key] === 'function') {
jsoned[key] = proto[key].bind(this);
return;
}
jsoned[key] = proto[key];
});
}
});
return jsoned;
}
But this is still not working. The resulted object includes only all the properties from all classes but only methods from PersonWorker.
What am I missing here?
Lots of answers already, but this is the simplest yet by using the spread syntax and de-structuring the object:
const {...object} = classInstance
This is what's working for me
const classToObject = theClass => {
const originalClass = theClass || {}
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(originalClass))
return keys.reduce((classAsObj, key) => {
classAsObj[key] = originalClass[key]
return classAsObj
}, {})
}
Ok, so the implementation in my OP was wrong, and the mistake was simply stupid.
The correct implementation when using es6 is:
toJSON(proto) {
let jsoned = {};
let toConvert = proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(jsoned);
return;
}
jsoned[prop] = val;
});
const inherited = Object.getPrototypeOf(toConvert);
if (inherited !== null) {
Object.keys(this.toJSON(inherited)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON')
return;
if (typeof inherited[key] === 'function') {
jsoned[key] = inherited[key].bind(jsoned);
return;
}
jsoned[key] = inherited[key];
});
}
return jsoned;
}
Here is the implementation for the toJSON() method. We are copying over the properties & methods from the current instance to a new object and excluding the unwanted methods i.e. toJSON and constructor.
toJSON() {
var jsonedObject = {};
for (var x in this) {
if (x === "toJSON" || x === "constructor") {
continue;
}
jsonedObject[x] = this[x];
}
return jsonedObject;
}
I have tested the object returned by toJSON() in Chrome and I see the object behaving the same way as you are expecting.
I'm riffing on Alex Cory's solution a lot, but this is what I came up with. It expects to be assigned to a class as a Function with a corresponding bind on this.
const toObject = function() {
const original = this || {};
const keys = Object.keys(this);
return keys.reduce((classAsObj, key) => {
if (typeof original[key] === 'object' && original[key].hasOwnProperty('toObject') )
classAsObj[key] = original[key].toObject();
else if (typeof original[key] === 'object' && original[key].hasOwnProperty('length')) {
classAsObj[key] = [];
for (var i = 0; i < original[key].length; i++) {
if (typeof original[key][i] === 'object' && original[key][i].hasOwnProperty('toObject')) {
classAsObj[key].push(original[key][i].toObject());
} else {
classAsObj[key].push(original[key][i]);
}
}
}
else if (typeof original[key] === 'function') { } //do nothing
else
classAsObj[key] = original[key];
return classAsObj;
}, {})
}
then if you're using TypeScript you can put this interface on any class that should be converted to an object:
export interface ToObject {
toObject: Function;
}
and then in your classes, don't forget to bind this
class TestClass implements ToObject {
toObject = toObject.bind(this);
}
This solution will lose methods, but it is a very simple solution to convert a class instance to an object.
obj = JSON.parse(JSON.stringify(classInstance))
using Lodash
This method isn't recursive.
toPlainObject() {
return _.pickBy(this, item => {
return (
!item ||
_.isString(item) ||
_.isArray(item) ||
_.isNumber(item) ||
_.isPlainObject(item)
);
});
}
Why system.js first performs __extends and then initializes?
Although I see no initialization at all since the first thing is called the __extends and throw out errors. How to fix it?
var __extends = (this && this.__extends) || function (d, b) {
console.log('set:__extends', d, b); // set:__extends undefined undefined
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};System.register(['some.js'], function(exports_1) {
console.log('set:exports', exports_1); // #####
var some_js_1;
var Index;
return {
setters:[
function (_some_js_1) {
console.log('set:setters'); // #####
some_js_1 = _some_js_1;
}],
execute: function() {
console.log('set:execute'); // #####
Index = (function (_super) {
console.log('set:before __extends'); // #####
__extends(Index, _super);
function Index() {
_super.call(this);
//console.log('some', some_js_1.SomeSuperClass);
}
return Index;
})(some_js_1.SomeSuperClass);
console.log('set:before exports_1'); // #####
exports_1("default", Index);
}
}
});
I'm looking for a simple way of creating two classes, one inheriting from the other, and the child redefining one of the parent's methods, and inside the new method, calling the parent's.
For example, having a class Animal and Dog, where the Animal class defines a method makeSound() which establishes how to output a sound, which Dog then overrides in its own makeSound() method to make a "woof" sound, but while also calling Animal's makeSound() to output that woof.
I looked at John Resig's model here, but it uses the native arguments.callee property which is apparently depreciated in ECMA script 5. Does that mean I shouldn't use John Resig's code?
What would one neat, simple way of writing my animal/dog code using Javascript's prototype inheritance model?
Does that mean I shouldn't use John Resig's code?
Correct, not when you are using ES5 in strict mode. However, it can be easily adapted:
/* Simple JavaScript Inheritance for ES 5.1
* based on http://ejohn.org/blog/simple-javascript-inheritance/
* (inspired by base2 and Prototype)
* MIT Licensed.
*/
(function(global) {
"use strict";
var fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
function BaseClass(){}
// Create a new Class that inherits from this class
BaseClass.extend = function(props) {
var _super = this.prototype;
// Set up the prototype to inherit from the base class
// (but without running the init constructor)
var proto = Object.create(_super);
// Copy the properties over onto the new prototype
for (var name in props) {
// Check if we're overwriting an existing function
proto[name] = typeof props[name] === "function" &&
typeof _super[name] == "function" && fnTest.test(props[name])
? (function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, props[name])
: props[name];
}
// The new constructor
var newClass = typeof proto.init === "function"
? proto.hasOwnProperty("init")
? proto.init // All construction is actually done in the init method
: function SubClass(){ _super.init.apply(this, arguments); }
: function EmptyClass(){};
// Populate our constructed prototype object
newClass.prototype = proto;
// Enforce the constructor to be what we expect
proto.constructor = newClass;
// And make this class extendable
newClass.extend = BaseClass.extend;
return newClass;
};
// export
global.Class = BaseClass;
})(this);
Prototype chain with Object.create() + assign constructor
function Shape () {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function (x, y) {
this.x += x;
this.y += y;
};
function Rectangle () {
Shape.apply(this, arguments); // super constructor w/ Rectangle configs if any
}
Rectangle.prototype = Object.create(Shape.prototype); // inherit Shape functionality
// works like Rectangle.prototype = new Shape() but WITHOUT invoking the constructor
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect instanceof Rectangle && rect instanceof Shape // returns true
from Object.create documentation
information about the new keyword
This is something I came up with for inheritance using chaining as well as allowing _super to work.
/**
* JavaScript simple inheritance
* by Alejandro Gonzalez Sole (base on John Resig's simple inheritance script)
* MIT Licensed.
**/
(function (){
var initializing = false,
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.* /;
function Class(){};
function inheritClass(superClass){
var self = this;
function Class(){
if (!initializing && typeof this._constructor === 'function')
this._constructor.apply(this, arguments);
}
Class.prototype = superClass.prototype;
Class.prototype._constructor = superClass;
Class.prototype.constructor = Class;
Class.extend = extendClass;
//currenlty if you inhert multiple classes it breaks
Class.inherit = inheritClass;
return Class;
};
function extendClass(prop) {
var self = this;
var _super = self.prototype;
function Class(){
if (!initializing && typeof this._constructor === 'function')
this._constructor.apply(this, arguments);
}
initializing = true;
var prototype = new self();
initializing = false;
for (var name in prop) {
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
this._super = _super[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) : prop[name];
}
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.extend = extendClass;
Class.inherit = inheritClass;
return Class;
};
Class.extend = extendClass;
Class.inherit = inheritClass;
})();
//EXAMPLE
function Person(){
this.name = "No name";
console.log("PERSON CLASS CONSTRUCTOR")
}
Person.prototype.myMethod = function (t){
console.log("MY PERSON", t, this.name);
return -1;
}
var TestPerson = Class.inherit(Person).extend({
_constructor: function(){
this._super();
this.name = "JOhn";
console.log("TEST PERSON CONSTRUCTOR");
},
myMethod: function (t){
console.log("TEST PERSON", t, this.name);
return this._super(t)
}
});
var test = new TestPerson();
console.log(test.myMethod("BA"));
I've been testing it on my pixi wrapper https://github.com/guatedude2/pixijs-cli so far it's been working very well for me.
The only issue i've encountered with this approach is that you can only inherit once. If you run inherit again it will override the previous inheritance.
I prefer the way TypeScript generates a form of inheritance (Select Simple Inheritance from the dropdown). That one doesn't use arguments.callee, but an __extends prototype.
var __extends = this.__extends || function (d, b) {
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function (meters) {
alert(this.name + " moved " + meters + "m.");
};
return Animal;
})();
var Snake = (function (_super) {
__extends(Snake, _super);
function Snake(name) {
_super.call(this, name);
}
Snake.prototype.move = function () {
alert("Slithering...");
_super.prototype.move.call(this, 5);
};
return Snake;
})(Animal);
var Horse = (function (_super) {
__extends(Horse, _super);
function Horse(name) {
_super.call(this, name);
}
Horse.prototype.move = function () {
alert("Galloping...");
_super.prototype.move.call(this, 45);
};
return Horse;
})(Animal);
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
I use Resig's makeClass() approach for constructors:
// makeClass - By John Resig (MIT Licensed)
// Allows either new User() or User() to be employed for construction.
function makeClass(){
return function(args){
if ( this instanceof arguments.callee ) {
if ( typeof this.init == "function" )
this.init.apply( this, (args && args.callee) ? args : arguments );
} else
return new arguments.callee( arguments );
};
}
// usage:
// ------
// class implementer:
// var MyType = makeClass();
// MyType.prototype.init = function(a,b,c) {/* ... */};
// ------
// class user:
// var instance = new MyType("cats", 17, "September");
// -or-
// var instance = MyType("cats", 17, "September");
//
var MyType = makeClass();
MyType.prototype.init = function(a,b,c) {
say("MyType init: hello");
};
MyType.prototype.Method1 = function() {
say("MyType.Method1: hello");
};
MyType.prototype.Subtype1 = makeClass();
MyType.prototype.Subtype1.prototype.init = function(name) {
say("MyType.Subtype1.init: (" + name + ")");
}
In that code, MyType() is a toplevel type, and MyType.Subtype1 is a nested type.
To use it, I can do:
var x = new MyType();
x.Method1();
var y = new x.Subtype1("y");
Can I get a reference to the instance of the parent type, within the init() for Subtype1() ?
How?
Nope, not unless you write a class implementation that tracks this "outer" class explicitly, Javascript won't be able to give this to you.
For example:
function Class(def) {
var rv = function(args) {
for(var key in def) {
if(typeof def[key] == "function" && typeof def[key].__isClassDefinition == "boolean")
def[key].prototype.outer = this;
this[key] = def[key];
}
if(typeof this.init == "function")
this.init.apply( this, (args && args.callee) ? args : arguments );
};
rv.prototype.outer = null;
rv.__isClassDefinition = true;
return rv;
}
var MyType = new Class({
init: function(a) {
say("MyType init: " + a);
say(this.outer);
},
Method1: function() {
say("MyType.Method1");
},
Subtype1: new Class({
init: function(b) {
say("Subtype1: " + b);
},
Method1: function() {
say("Subtype1.Method1");
this.outer.Method1();
}
})
});
var m = new MyType("test");
m.Method1();
var sub = new m.Subtype1("cheese");
sub.Method1();