0

The following code works perfectly... but it would seem using __proto__ is considered controversial. Is this true in the confines of Protractor/Nodejs? And if so, how else could I accomplish the same thing?

Given a basePage:

var BasePage = function() {
  this.to = function() {
    browser.get(this.url);
  };
};
module.exports = new BasePage;

And a page that would extend BasePage:

var basePage = require('../pages/basePage.js');

var MyPage = function() {
  this.__proto__ = basePage; // extend basePage...
  this.url = 'http://myPage.com';
};
module.exports = new MyPage;

When a test calls:

var myPage = require('../pages/myPage.js');

it('should go to page', function() {
  myPage.to();
}; 

Then win?

Brine
  • 3,733
  • 1
  • 21
  • 38
  • I think it's more conventional to call the base constructor inside the subclass constructor: `BasePage.call(this)`. That way the two prototypes are separate objects. – Austin Mullins Mar 03 '15 at 23:40
  • 1
    I would recommend you to use util.inherits: http://devdocs.io/node/util#util_util_inherits_constructor_superconstructor – Andres D Mar 04 '15 at 00:07

2 Answers2

3

but it would seem using__proto__ is considered controversial.

Yes.

Is this true in the confines of Protractor/Nodejs?

Yes, even though at least in the known environment you can be sure that it works.

And if so, how else could I accomplish the same thing?

There is no reason to set the __proto__ in the constructor like you do. That's what the .prototype property was made for! This will work exactly like your code:

var basePage = require('../pages/basePage.js');

var MyPage = function() {
  this.url = 'http://myPage.com';
};
MyPage.prototype = basePage; // extend basePage...
module.exports = new MyPage;

However, it's a bit strange that you export instances of your constructor. If your goal is to create singleton objects, don't use constructors and new. If your goal is to create a "class", you should export the constructor function (and do inheritance a bit different).

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks Bergi, this is down the line of what I was thinking... but alas, your solution fails with: `TypeError: Object # has no method 'to'` – Brine Mar 04 '15 at 01:46
  • @BrianRay: No it doesn't? Are you sure that you have placed the prototype assignment before the `module.exports = new MyPage;` line? – Bergi Mar 04 '15 at 02:06
  • Not sure what you mean... I'm following your listed example as listed, and it fails. Perhaps if you expand your example to what you mean? – Brine Mar 04 '15 at 02:16
  • Ahhh... now I'm with you. Thanks! – Brine Mar 04 '15 at 02:35
2

In the snippet below you can play around with different ideas involving prototypal inheritance. My personal take is that it's more conventional to call the base class constructor inside the subclass constructor. That way you can use your code in any browser as well as in Node.

var baseDiv = document.getElementById("base");
var subDiv = document.getElementById("sub");

var BaseClass = function BaseClassConstructor(div) {
    this.div  = div;
};

BaseClass.prototype.text = "I'm the base class!";

BaseClass.prototype.to = function BaseClassTo() {
  this.div.innerHTML = this.text;
}

// This SubClass calls the base class constructor on its "this" context.
var SubClass = function SubClassConstructor(div) {
  BaseClass.call(this, div);
};

// The prototype is then constructed by cloning the base class prototype.
SubClass.prototype = Object.create(BaseClass.prototype);

SubClass.prototype.text = "I'm the sub class!";

var b = new BaseClass(baseDiv);
var s = new SubClass(subDiv);

s.to();
b.to();
<div id="base"></div>
<div id="sub"></div>
Austin Mullins
  • 7,307
  • 2
  • 33
  • 48