Multiple inheritance console output - javascript

I am using below code. I'm getting wrong output console with my code. Right now i am getting "this is aB" but i required constructor related output on my output console. Like "this is aA" for first, "this is aB" for second, "this is aC" for third console.
function A () {
this.name = "A";
}
A.prototype.a = function () {
console.log("this is a"+this.name);
}
function B () {
this.name = "B";
}
B.prototype.b = function () {
console.log("this is b"+this.name);
}
function C() {
this.name = "C";
A.call(this);
B.call(this);
}
C.prototype = Object.assign({}, A.prototype, B.prototype);
C.prototype.constructor = C;
C.prototype.c = function () {
console.log("this is c"+this.name);
}
var x = new C();
x.a(); //this is aB
x.b(); //this is bB
x.c(); //this is cB

this in all three constructors refers to the same object: The one created by the new operator. That one object can only have one name property. So whichever constructor you call last will "win" and the name will be assigned by that. Thus, you're seeing B all the time because even with new C, first C writes C, then A writes A (overwriting C), and finally B writes B (overwriting A).
If you want the code related to each level in the hierarchy to have its own name property, you cannot literally do that, but you can get close by having each one use its own property (e.g., nameA, nameB, and nameC). You can do this in a way that doesn't require you to remember which level you're writing the code at by using brackets notation and a variable shared by all the code for each level.
I'm not recommending that. Whatever the actual problem you're trying to solve is, there's probably a better solution.
But here's how you'd do it:
var A = (function() {
var name = "nameA"; // <== We declare a variable and put this level's property name in it
function A() {
this[name] = "A"; // <== Note we're using brackets notation here
}
A.prototype.a = function() {
console.log("this is a: " + this[name]); // <== Brackets again here
};
return A;
})();
var B = (function() {
var name = "nameB"; // <== Same again for B
function B () {
A.call(this);
this[name] = "B";
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
B.prototype.b = function() {
console.log("this is b: " + this[name]);
};
return B;
})();
var C = (function() {
var name = "nameC";
function C() {
B.call(this);
this[name] = "C";
}
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
C.prototype.c = function() {
console.log("this is c: " + this[name]);
};
return C;
})();
var x = new C();
x.a(); //this is aA
x.b(); //this is bB
x.c(); //this is cC
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
The one object all three constructors work with will end up with three properties: nameA, nameB, and nameC.
Again, I'm not recommending that, just pointing out that it's possible, and can suit some problems, although it's unclear whether it suits yours.
That was 2016. Here in 2020, you'd probably solve this with private fields. You can use them with a transpiler now and support is being actively added to JavaScript engines:
// NOTE: Only works in environments that support private fields (such as
// modern Chromium-based browsers)
class A {
#name; // <== Private field, only accessible to A's code
constructor() {
this.#name = "A";
}
a() {
console.log("this is a: " + this.#name);
}
}
class B extends A {
#name; // <=== Private field, only accessible to B's code
constructor() {
super();
this.#name = "B";
}
b() {
console.log("this is b: " + this.#name);
}
}
class C extends B {
#name; // <=== Private field, only accessible to C's code
constructor() {
super();
this.#name = "C";
}
c() {
console.log("this is c: " + this.#name);
}
}
const x = new C();
x.a(); // tthis is a: A
x.b(); // tthis is b: B
x.c(); // tthis is c: C
The one object created by new C will have a different private #name field for each class.

Related

Dynamical inheritance TypeScript

JavaScript permit dynamical inheritance. I was wondering if TypeScript take it into account. The following code might illustrate the problem.
// inheritance.js
function fn1() {
this.a = "fn1";
}
function fn2() {
// ...
}
let f1 = new fn1(); // "instance" of fn1
let f2 = new fn2(); // "instance" of fn2
// inheritance
f2.__proto__ = f1;
// f2.a inherits from f1
console.log(f2.a); // output: "fn1"
As you can see we add an object f1, which is an instance of fn1, in the prototype chain of f2.
My question is therefore the following: can we reproduce this behave in TypeScript by using classes?
How would I change the following code to have the expected output?
// inheritance.ts
class class1 {
public a: string = "class1";
}
class class2 extends class1 {
// ...
}
let c1 = new class1();
let c2 = new class2();
console.log(c1.a); // output: "class1"
// this line would not work
c2.__proto__ = c1;
// change value c1.a
c1.a = "dynamical inheritance test";
console.log(c2.a); // should print value of c1.a (i.e "dynamical inheritance test")
I think what you are looking for is like an intersection mixing. There's a simple example found at the typescript docs. To do what you want, you, you can basically just assign the mixing's resulting class to the to inheriting class, then copy all properties of the class you want to be the extending to the result:
function extendDynamic<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
(<any>result) = (<any>first);
for (let it in second) {
if (second.hasOwnProperty(it)) {
(<any>result)[it] = (<any>second[it]);
}
}
return result;
}
class Class1 {
public a: string;
constructor(n: string) {
this.a = n;
}
}
class Class2 {
b: string = 'bbb';
}
const a = new Class1("bar");
const b = extendDynamic(a, new Class2());
a.a = 'foo';
console.log(b.a, b.b); // foo, bbb

JavaScript Class set itself

Its obvious that class properties can have it's own get and set functions.
But what about this?
As I tried so far, its legal to do something like this:
class Bind {
constructor(val) {
this.val = val;
}
set this(val) {
alert('not sure what happens here!');
}
get this() {
return this.val;
}
}
so these lines:
var b = new Bind(123);
b = 456;
should call the setter function, but the alert will never fire.
Any idea what that setter does?
b = 456;
Cause this does not change the previous value of b in any way, it just changes the previously stored reference into a value. A small example of what i mean:
let a = {it: "wont change" };
let b = a;
console.log(a, b);
b = 456;
console.log(a, b);
If rewriting b would change the referenced object in any way, a would change too.
Instead, You can reach the setter with:
b.this = 456;
class Person {
constructor(name) {
this._name = name;
}
get name() {
console.log("getter")
return this._name.toUpperCase();
}
set name(newName) {
console.log("setter")
this._name = newName;
}
}
let bob = new Person('Bob');
console.log(bob.name);// Outputs 'BOB'
bob.name = "new Bob"
console.log(bob.name); // Outputs 'NEW BOB'

How to share data with child classes

I need to be able to access a parent (not super) class from child classes.
In my case the data structure becomes exactly 3 levels deep:
Class A contains an array with x * Class B containing an array with y * Class C.
instances of Class C need to be able to access properties from Class A.
My idea was to pass down a callback, that would return the needed values.
I can not pass down static values from class A, since they can change over runtime.
Is this the proper way of handling the data flow between my instances, or can this be achieved in a more elegant way?
I set up a fiddle for this case (for the sake of simplicity only 2 levels deep): https://jsfiddle.net/2chngzqg/
class A {
constructor() {
this.foo = "bar";
}
shareProps = () => {
return this.foo;
}
createSubClass() {
this.sub = new B(this.shareProps);
}
}
class B {
constructor(callback) {
this.logShared = callback;
}
}
const a = new A();
a.createSubClass();
console.log(a.sub.logShared())
a.foo = 'baz';
console.log(a.sub.logShared())
How about that?.. In case the already mentioned Cart type contains a list of Product types and each product does list its Option types, and as seen from the example, each type is in control of how to create and/or add other depended types to it's list, then ... just provide this information about the hosting type to the constructor/factory function of the hosted type, thus every option features a product slot/property and every product features a cart slot/property.
The changed code of the OP's provided fiddle then might look like that ...
class Foo {
constructor(host) {
this.foo = "foo";
this.host = host;
}
createMember(Member) {
return (this.member = new Member(this));
}
}
class Bar {
constructor(host) {
this.bar = "bar";
this.host = host;
}
createMember(Member) {
return (this.member = new Member(this));
}
}
class Baz {
constructor(host) {
this.baz = "baz";
this.host = host;
}
createMember(Member) {
return (this.member = new Member(this));
}
}
var foo = (new Foo);
console.log('foo : ', foo);
console.log('foo.foo : ', foo.foo);
console.log('foo.member : ', foo.member);
console.log('foo.host : ', foo.host);
var bar = foo.createMember(Bar);
console.log('bar : ', bar);
console.log('bar.bar : ', bar.bar);
console.log('bar.member : ', bar.member);
console.log('bar.host : ', bar.host);
console.log('bar.host.host : ', bar.host.host);
var baz = bar.createMember(Baz);
console.log('baz : ', baz);
console.log('baz.baz : ', baz.baz);
console.log('baz.member : ', baz.member);
console.log('baz.host : ', baz.host);
console.log('baz.host.host : ', baz.host.host);
console.log('baz.host.host.host : ', baz.host.host.host);
.as-console-wrapper { max-height: 100%!important; top: 0; }
Although not es6 - you can achieve this using functional inheritance.
Using the Object that to hold the class properties. In this example B is instantiated onto the scope of A.
const A = () => {
let that = {}
// Public variable
that.foo = 'bar';
// Public function
that.shareProps = () => (that.foo);
// Subclass functions attached to this classes scope
that.createSubClass = () => {
that = B(that);
}
return that;
}
const B = (that) => {
that.logShared = () => (that.shareProps());
return that;
}
const a = A();
a.createSubClass();
console.log(a.logShared())
a.foo = 'baz';
console.log(a.logShared())
The 'sub classes' can be attached onto other public variables within the function if needs be.
JSFiddle
This is more flexible when you inherit from the 'parent' class in the 'child' classes because you always have access to whatever functions and variables are added to that.
const A = () => {
let that = {}
that.foo = 'bar';
that.shareProps = () => (that.foo);
return that;
}
const B = () => {
// A is inherited
let that = A();
that.logShared = () => (that.shareProps());
return that;
}
const C = () => {
// B is inherited
let that = B();
return that;
}
const c = C();
// Calls the function in B() => that.logShared()
console.log(c.logShared())
// Changes the value in A() => that.foo
c.foo = 'baz';
console.log(c.logShared())
See here for more examples of functional inheritance.

Understanding behavior of prototype - JavaScript

I don't understand why the following is happening:
I have the following code:
singleton = (function() {
somePrivFunction = function() {
return new B();
}
A = function() {};
B = function() {};
C = function() {};
A.prototype.a = function() { console.log("a"); };
B.prototype = A.prototype;
B.constructor = B;
B.prototype.b = function() { console.log("b"); };
C.prototype = A.prototype;
C.constructor = C;
C.prototype.c = function() { console.log("c"); };
return {
someFunction: function() {
return somePrivFunction();
}
}
})();
When I call singleton.someFunction() it returns me an instance of B. However all of the following work:
singleton.someFunction().b(); // Prints "b"
singleton.someFunction().a(); // Prints "a"
singleton.someFunction().c(); // Prints "c", but why? Shouldn't it be undefined?
B.prototype has a reference to the same object as A.prototype (line 12). On line 16 you stored a reference of this same object to C.prototype. This means all three prototypes point to the same object, therefore all changes made to A.prototype, B.prototype or C.prototype will actually change the same object. At the end of your code, this object has three methods: a, b and c.

JavaScript Object Mirroring/One-way Property Syncing

For security purposes, I have a need for a "mirrored" object. i.e. if I create object A, and shallow-clone a copy of A and call it B, whenever a property of A changes, I hope to have B automatically update itself to reflect the changes, but not the other way around. In other words, one-way property syncing.
My question: is there already a solution out in the wild that I'm not aware of?
Was thinking of implementing a library with observe-js (https://github.com/polymer/observe-js), but thought I should ask around before proceeding. Thanks.
Assuming you don't need to support IE8 and earlier, you can use getters to do that on modern browsers.
function proxy(src) {
var p = {};
Object.keys(src).forEach(function(key) {
Object.defineProperty(p, key, {
get: function() {
return src[key];
}
});
});
return p;
}
var a = {
foo: "Original foo",
bar: "Original bar"
};
var b = proxy(a);
console.log(b.foo); // "Original foo"
a.foo = "Updated foo"; // Note we're writing to a, not b
console.log(b.foo); // "Updated foo"
You can setup the prototype chain for this:
var a = {};
var Syncer = function(){};
Syncer.prototype = a;
var b = new Syncer();
a.foo = 123;
b.foo; // 123
b.bar = 456;
a.bar // undefined
Any property not set on b directly will be looked for on the prototype object, which is a.
You can even wrap this up in a convenience function:
var follow = function(source) {
var Follower = function(){};
Follower.prototype = source;
return new Follower();
}
var a = {};
var b = follow(a);
a.foo = 123;
b.bar = 456;
a.foo; // 123
b.foo; // 123
a.bar; // undefined
b.bar; // 456

Categories

Resources