How do I allow objects to inherit members from their class? - javascript

This question is about Javascript, however the first programming language I learned was Java so I relate to that the most easily.
In Java, objects have access to static members, as demonstrated in the article Understanding Class Members by Oracle:
public class Bicycle {
// INSTANCE fields
private int cadence;
private int gear;
private int speed;
// CONSTRUCTOR
constructor Bicycle(c,g,s) { /*...*/ }
//...
// STATIC fields
private static int numberOfBicycles = 0;
}
You can also refer to static fields with an object reference like
myBike.numberOfBicycles
In addition to objects having access to static fields, subclasses do as well, as mentioned in Inheritance.
public class MountainBike extends Bicycle {
public int seatHeight;
constructor MountainBike(c,g,s,h) { /*...*/ }
private static int mountainBikePrice = 324;
}
MountainBike now has 4 instance fields: cadence, gear, speed, and seatHeight; and 2 static fields: numberOfBicycles, and mountainBikePrice.
I would like to emulate this behavior in my Javascript program, however, since JS is prototype-oriented and not object-oriented, objects and subclasses cannot have access to their "class" members.
// constructor
function Bicycle(c,g,s) {
this.cadence = c
this.gear = g
this.speed = s
}
// instance methods
Bicycle.prototype.go = function () { /*...*/ }
Bicycle.prototype.stop = function () { /*...*/ }
// STATIC field
Bicycle.numberOfBicycles = 0 // <-- I want THIS field inherited
When I create a new Bicycle object via var myBike = new Bicycle(), I have access to the instance methods myBike.go(), etc., however I cannot get the static field via myBike.numberOfBicycles as I could in Java. The only way to get this is by calling Bicycle.numberOfBicycles.
Additionally, when I create a new subclass, it won't have access to its parent’s fields.
// subclass constructor
function MountainBike(c,g,s,h) {
Bicycle.call(this,c,g,s)
this.seatHeight = h
}
// vvvvvvvv extension mechanism... ignore this vvvvvvvvvv
MountainBike.prototype = Object.create(Bicycle.prototype)
MountainBike.prototype.constructor = MountainBike
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// STATIC field
MountainBike.mountainBikePrice = 324
If I call MountainBike.numberOfBicycles I get undefined (which would not happen in Java—it would return the parent’s value).
Other than assigning Bicycle.prototype.numberOfBicycles = 0, there must be an easier way for objects to inherit properties of their class, and subclasses to inherit properties of their parent.
Is there a way to access the object’s class, such as myBike.class? If so, then I could call myBike.class.numberOfBicycles.
Is there a way to access a subclass’s parent class, something like MountainBike.super?

Actually, the property you are looking for is constructor (as in myBike.constructor.numberOfBicycles works as intended).
The constructor of an object is (kind of) like the class of an instance in Java. It's probably best to take this with a grain of salt because the concepts are not exactly interchangeable.
Edit:
So I see you are basically trying to create some full implementation of "classes" in JavaScript using prototype and constructor hacks (which is fine really). Backbone has an interesting approach to this in their extend function. Relevant source is the following (see bottom of question for license of this code):
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
// Inherits constructor if not specified in child props.
if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); };
}
// copy all properties from parent and from static properties
// into child
_.extend(child, parent, staticProps);
// figure out child prototype (kind of like you had)
child.prototype = Object.create(parent.prototype);
_.extendOwn(child, protoProps);
child.prototype.constructor = child;
// Save super for later access (answers question 2)
child.__super__ = parent.prototype;
return child;
};
Annotations are mine. I edited the code to expose some similarities with what the OP had posted (i.e used Object.create instead of _.create). The way to use it is to set in the parent Parent.extend = extend; and then create the child class with Child = Parent.extend({...new properties and methods...},...).
I decided to go ahead and post the entire function because it might contain solutions to problems you haven't asked about yet (such as inheritance of constructors). Specifically for question 2, the Backbone devs made a decision to explicitly save the parent class in the child with __super__, so you could do that as well in your inheritance code (after you call the Object.create).
It also might just make more sense to use ES2015 Classes and inheritance with extends (here is some good docs on it). The support for it is not great, so you would need to use a preprocessor such as Babel. Here is an example of these classes:
class Parent {...}
class Child extends Parent {...}
License of Backbone code fragment posted:
(c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors.
Backbone may be freely distributed under the MIT license.
For all details and documentation:
http://backbonejs.org

Related

Understanding extend and method overwriting

This is a follow-up question from the previous: Why is the parent prototype method still executable after overriding?.
As we see, the literal object {metadata, aaa, init} was initialized by the extend function as a 2nd import variable, so this object should be the object automatically automatically instantiated and represents the extended sub-class. Then inside the object, it inherited the init method from its parent class and overrode it. first call the parent init method to trigger some necessary things, then setup the data for this extended component.
My question is: the init method in this literal object is its own init method, because this refered to the literal object, right? if it's yes, why I can't see it under this proprieties in my debugger tool.
enter image description here
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
"sap/ui/model/resource/ResourceModel",
], function (UIComponent, JSONModel, ResourceModel) {
"use strict";
return UIComponent.extend("sap.ui.demo.walkthrough.Component", {
metadata: {
"interfaces": [
"sap.ui.core.IAsyncContentCreation",
],
"rootView": {
"viewName": "sap.ui.demo.walkthrough.view.App",
"type": "XML",
/*"async": true, // implicitly set via the sap.ui.core.IAsyncContentCreation interface*/
"id": "app",
},
},
aaa: function () {
console.log("aaa");
},
init: function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient: {
name: "World",
},
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// set i18n model
var i18nModel = new ResourceModel({
bundleName: "sap.ui.demo.walkthrough.i18n.i18n",
});
this.setModel(i18nModel, "i18n");
},
});
});
Hope this other answer clears some things up:
__proto__ is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build __proto__ when you create an object with new
This means when you see methods in the prototype section it doesn't mean that the original parent class is overwritten. Your new "class" sap.ui.demo.walkthrough.Component also has/is a prototype and this (which is an instance of your new "class") has it's own __proto__. This new prototype/proto constains methods form the parent prototype and can also define new methods.
And from the documentation of sap.ui.base.Object.extend:
Creates a subclass of class sap.ui.base.Object with name sClassName and enriches it with the information contained in oClassInfo.
oClassInfo might contain three kinds of information:
[...]
any-other-name: any other property in the oClassInfo is copied into the prototype object of the newly created class. Callers can thereby add methods or properties to all instances of the class. [...]
So when you do this.__proto you will see the build plan for the current instance.
Do this.__proto__.__proto__ to get the build plan from the parent class. Do this.__proto__.__proto__.__proto__ to get the grand parent class (and so on).
The protos of the parent class are not affected by your child class. But your child classes include everything from the parent class. When you "override" a method you are are adding a method to your new prototype. The parent method still exists in the UIComponent prototype and can therefore be called by explicitly stating UIComponent.prototype.init.apply.

Best practice/only possibility. "Json to Javascript / Typescript Object by constructor"

I started developing with angular / typescript and created a service for my .NET Core API and I like to know what's the best way to get a clean and reliable object from my service.
I have an .NET CORE REST API returning a json result represented by the class definition below.
Service:
demoservice.getDemo().subscribe((val) => new Demo(val));
Demo-Class is the following code:
export class Demo {
public id : number;
public name : string;
public subDemo: SubDemo;
constructor(demo: Demo) {
this.id = demo.id;
this.name = demo.name;
this.subDemo = new SubDemo(demo.subDemo);
}
}
export class SubDemo {
public demoList : ListDemo[]
constructor(subDemo: SubDemo) {
this.demoList = new Array<ListDemo>();
subDemo.demoList.forEach(dl => {
this.demoList.push(new ListDemo(dl))
});
}
}
export class ListDemo {
constructor(listdemo : ListDemo) {
this.birthday = listdemo.birthday;
this.smoker = listdemo.smoker;
}
get birthDayFormatted() : Date {
return new Date(this.birthday);
}
public birthday : string;
public smoker : boolean;
}
I this the best way (full implement all constructors) to create a object. Please note I like to use the "getter" - functionality of my ListDemo Class.
Is there no better way? I just found some Object.clone / Object.assign / Object.create.
But none of this solution is comprehensive...
I am really interested in your experience..
Since you're using better & best I will answer with my, probably unwanted, opinion. Disclaimer: I'm no guru, this answer is based on opinion, feel free to disregard.
Don't do it. Your server has a set of objects in its domain, probably some kind of problem solving or data storage domain.
Your client has a set of objects in its domain, typically focused on presenting the data to the user and allowing the user to understand and manipulate it.
Both of these domains may have objects that have the same name or are based on the same real world concept. It can be tempting to feel like they are the same domain with the same objects. They are not. If they were the same you would not be writing a client and a server you would be writing two of the same thing. The two should communicate with pure data objects. In TS this means you should only create an interface, not a class, for the objects you receive from the server.
Instead, start over. Create a new domain based on what you want to appear in the API. If you design your API from the top (UI) down to the bottom (access services) you'll likely find that you don't have a one-to-one mapping between objects. On the occasions you do then you can probably get away with the occasional assign / merge (see below) but I've personally never found reason to do more than what you posted above.
Should you persist you may come across the option to reassign the prototype of the JSON literal from the base object to the class the data represents but that is a contentious topic and potential performance pitfall.. Your best bet is probably to just do a recursive/deep assign like Lodash's merge.
Just use interfaces not classes.
export interface Demo {
id: number;
name: string;
subDemo: SubDemo;
}
export interface SubDemo {
demoList: ListDemo[];
}
export interface ListDemo {
birthday: string;
smoker: boolean;
}
and your api should return the same shape, you should just be able to go
getDemo(): Observable<Demo> {
return this.http.get<Demo>('url');
}
in your service and in your component assign it to a property
demo$ = this.service.getDemo();
and then use the observable with the async pipe in your template.
<ng-container *ngIf="demo$ | async as demo">
{{ demo | json }}
</ng-container>
The less you have to manipulate your data the better. I have a VS pluging that allows you to paste C# classes into TS files and it converts them to TypeScript interfaces on the fly.

Nested Page Objects in Protractor

The Question:
What is the canonical way to define nested Page Objects in Protractor?
Use Case:
We have a complicated page that consists of multiple parts: a filter panel, a grid, a summary part, a control panel on a side. Putting all the element and method definitions into a single file and a single page object does not work and scale - it is becoming a mess which is difficult to maintain.
This is more of a general topic when it comes to Page Objects and how to maintain them. Sometime back I stumbled upon one of the Page Object Design Pattern techniques which I liked and made a lot of sense to me.
Rather than instantiating child page objects in the parent page objects, it would be ideal to follow javascript's Prototypal Inheritance concept. This has quite a number of benefits but first let me show how we can achieve it:
First we would create our parent page object ParentPage:
// parentPage.js
var ParentPage = function () {
// defining common elements
this.someElement = element(by.id("someid"));
// defining common methods
ParentPage.prototype.open = function (path) {
browser.get('/' + path)
}
}
module.exports = new ParentPage(); //export instance of this parent page object
We will always export an instance of a page object and never create that instance in the test. Since we are writing end to end tests we always see the page as a stateless construct the same way as each http request is a stateless construct.
Now let's create our child page objects ChildPage, we would use Object.create method to inherit the prototype of our parent page:
//childPage.js
var ParentPage = require('./parentPage')
var ChildPage = Object.create(ParentPage, {
/**
* define elements
*/
username: { get: function () { return element(by.css('#username')); } },
password: { get: function () { return element(by.css('#password')); } },
form: { get: function () { return element(by.css('#login')); } },
/**
* define or overwrite parent page methods
*/
open: { value: function() {
ParentPage.open.call(this, 'login'); // we are overriding parent page's open method
} },
submit: { value: function() {
this.form.click();
} }
});
module.exports = ChildPage
we are defining locators in getter functions, These functions get evaluated when you actually access the property and not when you generate the object. With that you always request the element before you do an action on it.
The Object.create method returns an instance of that page so we can start using it right away.
// childPage.spec.js
var ChildPage = require('../pageobjects/childPage');
describe('login form', function () {
it('test user login', function () {
ChildPage.open();
ChildPage.username.sendKeys('foo');
ChildPage.password.sendKeys('bar');
ChildPage.submit();
});
Notice above that we are only requiring the child page object and utilizing/overriding parent page objects in our specs. Following are the benefits of this design pattern:
removes tight coupling between parent and child page objects
promotes inheritance between page objects
lazy loading of elements
encapsulation of methods and action
cleaner & much easier to understand the elements relationship instead of parentPage.childPage.someElement.click();
I found this design pattern in webdriverIO's developer guide, most of the above methods I explained are taken from that guide. Feel free to explore it and let me know your thoughts!
The idea is define the Page Object as a package - directory with index.js as an entry point. The parent page object would act as a container for child page objects which in this case have a "part of a screen" meaning.
The parent page object would be defined inside the index.js and it would contain all the child page object definitions, for example:
var ChildPage1 = require("./page.child1.po"),
ChildPage2 = require("./page.child2.po"),
var ParentPage = function () {
// some elements and methods can be defined on this level as well
this.someElement = element(by.id("someid"));
// child page objects
this.childPage1 = new ChildPage1(this);
this.childPage2 = new ChildPage2(this);
}
module.exports = new ParentPage();
Note how this is passed into the child page object constructors.
This might be needed if a child page object would need access to the
parent page object's elements or methods.
The child Page Object would look like this:
var ChildPage1 = function (parent) {
// element and method definitions here
this.someOtherElement = element(by.id("someotherid"));
}
module.exports = ChildPage1;
Now, it would be quite convenient to use this kind of page object. You simply require the parent page object and use the dot notation to get access to the sub page objects:
var parentPage = requirePO("parent");
describe("Test Something", function () {
it("should test something", function () {
// accessing parent
parentPage.someElement.click();
// accessing nested page object
parentPage.childPage1.someOtherElement.sendKeys("test");
});
});
requirePO() is a helper function to ease imports.
Sample nested page object directory structure from one of our test automation projects:
I don't use Protractor, but maybe you can try the idea below - at least, it's been working well for me so far:
I use something you can call "Component Object" - I divide a page into components or parts, and suppose I am given the scope of each component, I search and add elements to the components based on their scopes. This way, I can easily reuse the same/similar components in different pages.
For example, with the page http://google.com, I divide it into 3 parts:
Let's say we will name those 3 parts as: Header, SearchForm, Footer
The code for each part will be something like this:
class Header {
public Header(SearchContext context){
_context = context;
}
WebElement GmailLink {
get {
return _context.FindElement(By.CssSelector("[data-pid='23']"));
}
}
WebElement ImagesLink {
get {
return _context.FindElement(By.CssSelector("[data-pid='2']"));
}
}
SearchContext _context;
}
class SearchForm{
public Header(SearchContext context){
_context = context;
}
WebElement SearchTextBox {
get {
return _context.FindElement(By.Name("q")):
}
}
WebElement SearchButton {
get {
return _context.FindElement(By.Name("btnK")):
}
}
SearchContext _context;
}
..
And the code for the page google.com will be like:
class GoogleComPage{
WebDriver _driver;
public GoogleCompage(driver){
_driver = driver;
}
public Header Header{
get {
return new Header(_driver.FindElement(By.Id("gb")));
}
}
public SearchForm SearchForm{
get {
return new SearchForm(_driver.FindElement(By.Id("tsf")));
}
}
}

What to use for data-only objects in TypeScript: Class or Interface?

I have a bunch of data-only "classes" (in .NET world we call them POCO objects) that does not have any methods or even constructors. Examples are Customer, Product, User entities, you name it...
Originally I started using typescript classes but now I'm thinking that declaring them as interface might be better. From performance standpoint, and not only... It's just that in C# we're used to use interfaces for different thing, and for "POCO" (Plain-old-clr-object, or "data-only" object) we use just a class (sometimes even struct).
What is a proper way to declare them in TypeScript?
Note that I mostly understand (I think) technical differences between class and interface (i.e. that interface is a compile-time construct), but I'm trying to find out which one fits this case semantically.
P.S.: I've seen similar questions (like this) but none of them adress this specific issue clearly and definitely, so please don't close this as 'possible duplicate' or 'opinion-based' (cause it isn't) :)
Interface and it's not even close.
People start writing TypeScript and they suddenly think they have to use classes for some reason. But they don't. Classes are an ES6 feature and they work fine, but if it's just data, it's just data.
A major problem with using classes is that they won't serialize/deserialize like you expect over the wire, so things like instanceof checks won't work.
One rule of thumb is that if there's not internal state associated with some methods, and there's no need for traditional OO polymorphism, don't use a class. This even extends to static classes -- use namespace / module instead.
Use classes with parameter properties:
// Immutable data object
class Person {
constructor(readonly firstName: String, readonly lastName: String) {}
}
// Mutable data object
class Person {
constructor(public firstName: String, public lastName: String) {}
}
I use classes for my data in Typescript, as I allways did in C# C++ Java, and only use interfaces for dependency injection. Interfaces have not be thought for manipulating data.
In my application model, if I need to write a method that uses some datas of the same class, then the class is better place to go for that method. Adding getters and setters that transform your properties is a great flexibility.
I am not a javascript programmer so when I need to create an object, I don't like using data only object where properties can by anything. I create an instance of class by the way of the constructors that have been defined for that class.
When I receive data from a service, I don't deserialize a class: I deserialize the json data and I create my instance with that data. Here is the way for building my model from the received data:
// ajax callback for diaries
onReceiveDiary( jsonDiary : any )
{
let newDiary = new Diary ( jsonDiary );
// now I can call methods on the object:
let ok : boolean = newDiary.CheckIfCompleted();
}
In the class I add a constructor with the only one dependency on the json object:
export class Diary
{
title : string;
article : Article;
constructor( json : any )
{
// the trick for setting all the object properties
$.extend( this, json);
this.article = new Article( json.article );
}
}
Or we can create a factory for building objects using the default constructor:
let newDiary = new Diary ();
$.extend( newDiary, jsonDiary );
newDiary.article = $.extend( new Article(), jsonDiary.article );

ExtJS how to override singleton constructor

I am having a hard time overriding a constructor from a singleton class in ExtJS 4.1. I have an override defined, but by the time my override statement gets processed, the constructor has already executed.
Ext.define('singleton', {
singleton: true,
constructor: function() {
alert('replace me');
}
});
Overriding the constructor of a singleton doesn't make sense, a singleton is a class that is very early on in the execution of Extjs turned into an instance of itself. This means that you are trying to override an instance of a class and not the class itself.
I can recommend that whatever you want done to the singleton be done in a separate method in the class definition that you can call very early in Ext.onReady() or your apps instantiation.
You can't override a singleton class, that is true, but you can override the singleton instance:
Ext.define('singleton', {
singleton: true,
constructor: function() {
// does whatever
}
});
Ext.define('singletonOverride', {
override: 'singleton',
// adding new property
foo: 'bar',
// adding new method
baz: function() {},
initSingletonOverride: function() {
// do whatever is needed
// to augment the singleton
// behavior the way you want
}
},
function() {
// `this` is the singleton instance
this.initSingletonOverride();
});
Keep in mind that all this fluff comes down to the JavaScript objects. A class is an Object, and a class instance is another Object. You can override either of them, or both; the class system is here to help you not to lose track of what you're doing.

Categories

Resources