Skip to content

Instantly share code, notes, and snippets.

@wentout
Last active August 29, 2019 07:05
Show Gist options
  • Save wentout/47eb0fd224e69b65b3efddbcb6741408 to your computer and use it in GitHub Desktop.
Save wentout/47eb0fd224e69b65b3efddbcb6741408 to your computer and use it in GitHub Desktop.
Inheritance Map Example
'use strict';
// Inheritance Map Example
const assert = require('assert');
const { strictEqual, deepStrictEqual } = assert;
const util = require('util');
const inspect = (value) => {
return util.inspect(value, {
colors : true,
compact : false
})
};
const userTypePrototypeDesc = 'User ETL~DFD: Init';
const createUserType = function () {
var UserType = function({ email, password } = userData) {
this.email = email;
this.password = password;
return this;
};
UserType.prototype.description = userTypePrototypeDesc;
UserType.prototype.email = '';
UserType.prototype.password = '';
return UserType;
};
const UserWithoutPasswordTypePrototypeDesc = 'User ETL~DFD: No Password'; // used for checking, unnecessary
// so... it must be reproducible
const createNewUserWithoutPasswordType = function () {
const UserWithoutPasswordType = function() {
// delete this.password;
// does not work
// cause property deletion
// will cast prototype chain
// backing prop to place
// instead the following will
// cause we use memory block
// by setting it to undefined
// and, moreover, through this
// we will see our data change
// cause prop will exist
// but we changed it to undefined
// it is not rude, just SOLID
// and DFD ~ SADT transformations
// and ETL concept in rush :)
this.password = undefined;
return this;
};
UserWithoutPasswordType.prototype.description = UserWithoutPasswordTypePrototypeDesc; // used for checking, unnecessary
return UserWithoutPasswordType;
};
// so... it must be reproducible
const createNewUserDataTypeExampleModType = function () {
const UserWithExampleModificationType = function(initWith = 'none') {
this.modificationExampe = `done : ${initWith}`;
return this;
};
return UserWithExampleModificationType;
};
const createNewUserDataTypeExampleModTypeNext = function () {
const UserWithExampleModificationTypeNext = function(initWith = 'none') {
this.modificationExampeNext = `next : ${initWith}`;
return this;
};
return UserWithExampleModificationTypeNext;
};
const createMoreDeep = function () {
const MoreDeep = function(initWith = 'none') {
this.moreDeep = `moreDeep : ${initWith}`;
return this;
};
return MoreDeep;
};
const createEvenMoreDeep = function () {
const EvenMoreDeep = function(initWith = 'none') {
this.evenMoreDeep = `EvenMoreDeep : ${initWith}`;
return this;
};
return EvenMoreDeep;
};
// inherited props collector
const finalizeES5 = function (result = {}) {
let self = this;
const copyProps = () => {
Object.entries(self).forEach(([key, value] = entry) => {
if (!result.hasOwnProperty(key)) {
if (key !== 'constructor') {
result[key] = value;
}
}
});
};
copyProps();
let proto = Object.getPrototypeOf(self);
while (proto) {
if (proto) {
self = proto;
copyProps();
proto = Object.getPrototypeOf(self);
} else {
break;
}
};
return result;
};
// inherited props collector ancient style
var finalize = function() {
var result = {};
// Important : nested props are also copied !
for (var i in this) {
// should check if constructor is the same
// but for this example just get rid of it
// cause it is simply not the same
// for inherited instances
if (i !== 'constructor') {
result[i] = this[i];
}
}
return result;
};
// so we should create function
// which will return proper constructor
// of modificatorType constructors
// inherited from existent instance
// meaning existent instance is "this" keyword
const DataModificationConstructor = function (ModificatorType) {
const self = this;
if (!self || !self.constructor) {
throw new Error('Wrong Modification Pattern!');
}
if (self instanceof ModificatorType) {
throw new Error('attempt to repeat the same inheritance');
}
// console.log('\n\n\n', selfInstance === self, '\n\n\n'); // false
// console.log('\n\n\n', selfInstance instanceof self.constructor, '\n\n\n'); // true
const ModificatorTypeProto = ModificatorType.prototype;
const ModificatorTypeConstructor = ModificatorType.prototype.constructor;
var inheritedInstance;
var dataModificatorInstance;
const DataModificatorInheridedType = function () {
const UpperClosureType = function () {
const willBeModifiedInstance = this;
const ModificatorInheridedType = function (...args) {
// const prevCstr = this.constructor;
// make modification itself
// ModificatorTypeConstructor.call(this, ...args);
// Object.setPrototypeOf(DataModificatorInheridedType.prototype, ModificatorTypeProto);
// Object.setPrototypeOf(inheritedInstance, ModificatorTypeProto);
// Object.setPrototypeOf(dataModificatorInstance, ModificatorTypeProto);
ModificatorType.prototype.constructor.prototype = this;
// ModificatorType.prototype.constructor.prototype.constructor = ModificatorType;
inheritedInstance = new ModificatorType(...args);
// TODO : 3) should try to reorganize it
// leaving inheritedInstance.constructor.prototype untouched
Object.defineProperty(inheritedInstance.constructor.prototype, 'constructor', {
value : ModificatorType,
// TODO : !!! закомментировать и разобраться
writable : true
});
Object.defineProperty(inheritedInstance.constructor.prototype.constructor.prototype.constructor, 'prototype', {
// might be the same as above
// Object.defineProperty(inheritedInstance.constructor.prototype.constructor, 'prototype', {
value : ModificatorInheridedType.prototype
});
// inheritedInstance.constructor.prototype.constructor = ModificatorType;
// inheritedInstance.constructor.prototype.constructor.prototype.constructor.prototype = ModificatorInheridedType.prototype;
return inheritedInstance;
};
ModificatorInheridedType.prototype = willBeModifiedInstance;
// ModificatorInheridedType.prototype.constructor = ModificatorInheridedType;
// the line upper is equal
// to the line below
// but, below example is not enumerable
// and we got rid of this constructor appear in log
// where "... yes ... this is a sorrow ..."
Object.defineProperty(ModificatorInheridedType.prototype, 'constructor', {
value : ModificatorInheridedType,
// TODO : !!! закомментировать и разобраться
writable : true
});
Object.entries(ModificatorTypeProto).forEach(([key, value] = entry) => {
if (!ModificatorInheridedType.prototype.hasOwnProperty(key)) {
ModificatorInheridedType.prototype[key] = undefined;
ModificatorInheridedType.prototype[key] = ModificatorTypeProto[key];
}
});
return ModificatorInheridedType;
};
UpperClosureType.prototype = this;
if (!ModificatorTypeProto.hasOwnProperty('desciption')) {
UpperClosureType.prototype.description = ModificatorType.prototype.constructor.name;
}
return new UpperClosureType();
};
DataModificatorInheridedType.prototype = self;
dataModificatorInstance = new DataModificatorInheridedType();
// DataModificatorInheridedType.prototype = dataModificatorInstance;
// DataModificatorInheridedType.prototype.constructor = ModificatorType;
return dataModificatorInstance;
};
console.log('\n\n: STARTING :\n\n');
const UserType = createUserType();
const UserTypeModification =
DataModificationConstructor.call(Object.create({}), UserType);
debugger;
const userInstance = new UserTypeModification({
email: 'went.out@gmail.com',
password: 123
});
console.log('1. By default userInstance.prototype is not referenced :', userInstance.prototype);
console.log('2. But constructor is, and points to : ', userInstance.constructor.name,
` : ${UserType.name === userInstance.constructor.name}`);
const userInstanedBefore = inspect(userInstance);
console.log('3. And userInstance value till this moment is :');
console.log(userInstanedBefore);
var callsAmount = 0;
// if we will cast this line
// directly before calling
// const userWithoutPassword = new UserWithoutPasswordTypeModificator();
// it will fail inheritance
// this cycle closure is unnecessary
// just demonstration it still works
const InstanceClosures = [1, 2, 3];
const InstanceClosuresLength = InstanceClosures.length;
const punchlines = {};
const printPunchlines = () => {
console.log('\n\n\n\n');
console.log('****************************************************************************************************');
console.log('\n');
Object.values(punchlines).forEach(({
start,
end
} = punchline) => {
console.log('\n\n');
start();
console.log();
end();
});
console.log('\n\n\n');
console.log('****************************************************************************************************');
console.log('\n');
};
// here we make scoped instances
InstanceClosures
.map(function (num) {
// just for checking ;^)
// thought if we will create DataModificationConstructor
// in this scope, userWithoutPassword will inherit addition property
// userInstance.addition = num;
const UserWithoutPasswordType = createNewUserWithoutPasswordType();
const UserWithoutPasswordTypeModificator
= DataModificationConstructor.call(userInstance, UserWithoutPasswordType);
const userWithoutPassword = new UserWithoutPasswordTypeModificator();
// inherited from the same user instance
// and with absolutely the same inithal data
// but with different pointer to that data
const anotherUserWithoutPassword = new UserWithoutPasswordTypeModificator();
const AdditionalModificatorType = createNewUserDataTypeExampleModType();
const AdditionalModificatorTypeModificator
= DataModificationConstructor.call(anotherUserWithoutPassword, AdditionalModificatorType);
const userWithoutPasswordWithAdditionalModification = new AdditionalModificatorTypeModificator(num);
const AdditionalModificatorTypeNext = createNewUserDataTypeExampleModTypeNext();
const AdditionalModificatorTypeModificatorNext
= DataModificationConstructor.call(userWithoutPasswordWithAdditionalModification, AdditionalModificatorTypeNext);
const userWithoutPasswordWithAdditionalModificationNext = new AdditionalModificatorTypeModificatorNext(num);
const MoreDeep = createMoreDeep();
const MoreDeepTypeModificator
= DataModificationConstructor.call(userWithoutPasswordWithAdditionalModificationNext, MoreDeep);
const moreDeep = new MoreDeepTypeModificator(num);
const EvenMoreDeep = createEvenMoreDeep();
const EvenMoreDeepTypeModificator
= DataModificationConstructor.call(moreDeep, EvenMoreDeep);
const evenMoreDeep = new EvenMoreDeepTypeModificator(num);
debugger;
const finMD = finalize.call(moreDeep);
const finEMD = finalize.call(evenMoreDeep);
debugger;
userWithoutPassword.sign = `userWithoutPassword.sign : ${num}`;
anotherUserWithoutPassword.sign = `anotherUserWithoutPassword.sign : ${num}`;
const inUserType = userWithoutPassword instanceof UserType;
const inUserWPType = userWithoutPassword instanceof UserWithoutPasswordType;
const inUserWPTypeModificator = userWithoutPassword instanceof UserWithoutPasswordTypeModificator;
const inBoth = inUserType && inUserWPType;
const result = {
num,
userInstance,
userWithoutPassword,
anotherUserWithoutPassword,
userWithoutPasswordWithAdditionalModification,
UserWithoutPasswordType,
UserWithoutPasswordTypeModificator,
inUserType,
inUserWPType,
inUserWPTypeModificator,
inBoth,
};
punchlines[num] = {
start : () => {
console.log(`PUNCHLINE ::: START ::: ${num}`);
console.log('XXX : userWithoutPassword instanceof UserType : ', inUserType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordType : ', inUserWPType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordTypeModificator : ', inUserWPTypeModificator);
console.log('This tells us, that immediately after Instance Creation everything was : ', inBoth ? 'OK!' : 'FAILED!');
console.log('YYY : userWithoutPasswordWithAdditionalModification instanceof UserType : ',
userWithoutPasswordWithAdditionalModification instanceof UserType);
console.log('YYY : userWithoutPasswordWithAdditionalModification instanceof UserWithoutPasswordType : ',
userWithoutPasswordWithAdditionalModification instanceof UserWithoutPasswordType);
console.log('YYY : userWithoutPasswordWithAdditionalModification instanceof AdditionalModificatorType : ',
userWithoutPasswordWithAdditionalModification instanceof AdditionalModificatorType);
console.log('YYY : userWithoutPasswordWithAdditionalModification instanceof AdditionalModificatorTypeModificator : ',
userWithoutPasswordWithAdditionalModification instanceof AdditionalModificatorTypeModificator);
console.log('YYY : userWithoutPasswordWithAdditionalModification.constructor : ',
userWithoutPasswordWithAdditionalModification.constructor.name);
}
};
return result;
})
.forEach(({
num,
userInstance,
userWithoutPassword,
anotherUserWithoutPassword,
userWithoutPasswordWithAdditionalModification,
UserWithoutPasswordType,
UserWithoutPasswordTypeModificator,
inUserType,
inUserWPType,
inUserWPTypeModificator,
inBoth,
} = result) => {
// and here we check they are inherited properly
setTimeout(() => {
callsAmount++;
console.log(`\n\n\n: BOOM ${num} :\n\n`);
const stillInUserType = userWithoutPassword instanceof UserType;
const stillInUserWPType = userWithoutPassword instanceof UserWithoutPasswordType;
const stillInUserWPTypeModificator = userWithoutPassword instanceof UserWithoutPasswordTypeModificator;
punchlines[num].end = () => {
console.log(`PUNCHLINE ::: END ::: ${num}`, 'of', InstanceClosuresLength);
console.log('XXX : userWithoutPassword instanceof UserType : ',
stillInUserType, ' : expected : ', inUserType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordType : ',
stillInUserWPType, ' : expected : ', inUserWPType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordTypeModificator : ',
stillInUserWPTypeModificator, ' : expected : ', inUserWPTypeModificator);
};
console.log('4. The prototype of userWithoutPassword instance is not referenced also :', userWithoutPassword.prototype);
const isReferenced = UserWithoutPasswordType.name === userWithoutPassword.constructor.name;
console.log('5. And the constructor still does, and points to : ', UserWithoutPasswordType.name,
` : ${isReferenced}`, isReferenced ? ': as expected' : ': not expected');
console.log('\n');
const userInstanedAfter = inspect(userInstance);
console.log('6.1 And userInstance is as before :', userInstanedAfter === userInstanedBefore ? 'equal ': 'not equal');
console.log(userInstanedAfter);
console.log('\n');
console.log('6.2 userInstance constructor still points to : ', userInstance.constructor.name,
` : ${UserType.name === userInstance.constructor.name}`);
console.log('\n\n: AND :\n\n');
console.log('7.1 userWithoutPassword.email by reference to prototype is : ', userWithoutPassword.email);
console.log('7.2 userWithoutPassword.hasOwnProperty("email") is : ', userWithoutPassword.hasOwnProperty('email'),
userWithoutPassword.hasOwnProperty('email') ? ' : unexpected' : ' : as expected'); // false
console.log('7.3 userWithoutPassword.hasOwnProperty("password") is : ', userWithoutPassword.hasOwnProperty('password'));
console.log('7.4 userWithoutPassword.hasOwnProperty("constructor") is : ', userWithoutPassword.hasOwnProperty('constructor'),
userWithoutPassword.hasOwnProperty('constructor') ? ' : unexpected' : ' : as expected'); // false
console.log('7.5 userWithoutPassword.hasOwnProperty("description") is : ', userWithoutPassword.hasOwnProperty('description'),
userWithoutPassword.hasOwnProperty('description') ? ' : unexpected' : ' : as expected'); // false
console.log('\n: top :\n');
console.log('8. userWithoutPassword.password is : ', userWithoutPassword.password, userWithoutPassword.password === undefined ? ' : as expedted' : ' : not expected');
console.log('\n\n: CHECKING :\n\n');
const userLogDataAncientWay = finalize.call(userInstance);
console.log(
'Logging via Ancient Way [ userInstance ]',
Object.keys(userLogDataAncientWay),
);
console.log(inspect(userLogDataAncientWay));
const userLogDataNewWay = finalizeES5.call(userInstance);
console.log(
'Logging via modern ES Way [ userInstance ]',
Object.keys(userLogDataNewWay),
);
console.log(inspect(userLogDataNewWay));
console.log('\n');
const userWithoutPasswordLogDataAncientWay = finalize.call(userWithoutPassword);
console.log(
'Logging via Ancient Way [ userWithoutPassword ]',
Object.keys(userWithoutPasswordLogDataAncientWay),
);
console.log(inspect(userWithoutPasswordLogDataAncientWay));
const userWithoutPasswordLogDataNewWay = finalizeES5.call(userWithoutPassword);
console.log(
'Logging via modern ES Way [ userWithoutPassword ]',
Object.keys(userWithoutPasswordLogDataNewWay),
);
console.log(inspect(userWithoutPasswordLogDataNewWay));
console.log('\n');
const anotherUserWithoutPasswordLogDataAncientWay = finalize.call(anotherUserWithoutPassword);
console.log(
'Logging via Ancient Way [ anotherUserWithoutPassword ]',
Object.keys(anotherUserWithoutPasswordLogDataAncientWay),
);
console.log(inspect(anotherUserWithoutPasswordLogDataAncientWay));
const anotherUserWithoutPasswordLogDataNewWay = finalizeES5.call(anotherUserWithoutPassword);
console.log(
'Logging via modern ES Way [ anotherUserWithoutPassword ]',
Object.keys(anotherUserWithoutPasswordLogDataNewWay),
);
console.log(inspect(anotherUserWithoutPasswordLogDataNewWay));
console.log('\n');
const userWithoutPasswordWithAdditionalModificationLogData =
finalizeES5.call(userWithoutPasswordWithAdditionalModification);
console.log(
'Logging via modern ES Way [ userWithoutPasswordWithAdditionalModificationLogData ]',
Object.keys(userWithoutPasswordWithAdditionalModificationLogData),
);
console.log(inspect(userWithoutPasswordWithAdditionalModificationLogData));
// console.log(userWithoutPasswordLogDataNewWay.hasOwnProperty('constructor'));
// console.log(userWithoutPassword.hasOwnProperty('constructor'));
console.log('\n\n');
// Does SOLID still exist?
const comparator = (title, expected, received) => {
try {
deepStrictEqual(expected, received);
return `${title} : passed`;
} catch (error) {
return `${title} : failed`;
}
};
console.log(
comparator(
'Comparator Equality Keys',
Object.keys(userWithoutPasswordLogDataAncientWay),
Object.keys(userWithoutPasswordLogDataNewWay)
)
);
console.log(
comparator(
'Comparator Equality Props',
inspect(userWithoutPasswordLogDataAncientWay),
inspect(userWithoutPasswordLogDataNewWay)
)
);
console.log(
comparator(
'must be still the same, unchanged',
UserType.prototype.description,
userTypePrototypeDesc
), ': UserType.prototype.description :',
UserType.prototype.description ===
userTypePrototypeDesc
);
console.log(
comparator(
'must be still the same, unchanged',
UserWithoutPasswordType.prototype.description,
UserWithoutPasswordTypePrototypeDesc
), ': UserWithoutPasswordType.prototype.desciption :',
UserWithoutPasswordType.prototype.description ===
UserWithoutPasswordTypePrototypeDesc
);
console.log('userInstance instanceof UserType : ', userInstance instanceof UserType);
console.log('userInstance ! instanceof UserWithoutPasswordType : ', !(userInstance instanceof UserWithoutPasswordType));
console.log('\n');
console.log(`PUNCHLINE ::: REPORT ${num}`);
console.log('XXX : userWithoutPassword instanceof UserType : ',
userWithoutPassword instanceof UserType, 'expected', inUserType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordType : ',
userWithoutPassword instanceof UserWithoutPasswordType, 'expected', inUserWPType);
console.log('XXX : userWithoutPassword instanceof UserWithoutPasswordTypeModificator : ',
stillInUserWPTypeModificator, ' : expected : ', inUserWPTypeModificator);
console.log('\n');
console.log('UserType ! instanceof UserWithoutPasswordType : ', !(UserType instanceof UserWithoutPasswordType));
console.log('UserType unchanged : ', UserType === userInstance.constructor);
console.log('UserType.prototype', UserType.prototype);
console.log('UserType.constructor', UserType.constructor);
console.log('UserType.constructor.prototype', UserType.constructor.prototype);
console.log();
console.log('UserWithoutPasswordType ! instanceof UserType : ', !(UserWithoutPasswordType instanceof UserType));
console.log('UserWithoutPasswordType unchanged : ', UserWithoutPasswordType === userWithoutPassword.constructor);
console.log('\nUserWithoutPasswordType.prototype', UserWithoutPasswordType.prototype);
console.log(`\n\t... yes ... this is a sorrow ...
look for
Object.defineProperty(ModificatorInheridedType.prototype, 'constructor'
upper of this code, and re-comment lines\n`);
console.log('UserWithoutPasswordType.constructor', UserWithoutPasswordType.constructor);
console.log('UserWithoutPasswordType.constructor.prototype', UserWithoutPasswordType.constructor.prototype);
console.log('\n\n\t... thought now we have the following : \n');
console.log('userWithoutPassword.constructor : ', userWithoutPassword.constructor.name);
console.log('userInstance.constructor : ', userInstance.constructor.name);
if (callsAmount === InstanceClosuresLength) {
printPunchlines();
}
}, 50);
});
'use strict';
// Transformation Card PoC
const assert = require('assert');
const { strictEqual, deepStrictEqual } = assert;
const util = require('util');
const inspect = (value) => {
return util.inspect(value, {
colors : true,
compact : false
})
};
const UserType = function ({ email, password } = userData) {
this.email = email;
this.password = password;
return this;
};
UserType.prototype.description = 'User ETL~DFD';
UserType.prototype.email = '';
UserType.prototype.password = '';
// starting
const user = new UserType({
email: 'went.out@gmail.com',
password: 123
});
// const user321 = new UserType({
// email: 'went.out@gmail.com',
// password: 321
// });
UserType.WithoutPassword = function () {
// now this referes to new empty object
// which we should fill
UserType;
UserType.WithoutPassword;
user;
// const formerUser = this.constructor.prototype.constructor.prototype;
this.password = undefined;
debugger;
this.constructor.prototype.constructor = UserType.WithoutPassword;
this.constructor.prototype.constructor.prototype.constructor = UserType;
debugger;
// this.constructor.prototype.constructor = UserType.WithoutPassword;
// return userWP;
};
UserType.WithoutPassword.prototype = user;
// so now UserType.WithoutPassword.prototype is user
// this means UserType.WithoutPassword.prototype.constructor is now UserType;
// and also means UserType.WithoutPassword.prototype.constructor.prototype is UserType.prototype;
// console.log(UserType.WithoutPassword.prototype.constructor.prototype.constructor === UserType);
// mooving it deeper
// UserType.WithoutPassword
// .prototype.constructor
// .prototype.constructor
// .prototype.constructor.prototype =
// UserType.WithoutPassword.prototype;
const userWP = new UserType.WithoutPassword();
console.log('user instanceof UserType', user instanceof UserType);
console.log('userWP instanceof UserType', userWP instanceof UserType);
console.log('userWP instanceof UserType.WithoutPassword', userWP instanceof UserType.WithoutPassword);
console.log('user.constructor.name :', user.constructor.name);
console.log('userWP.constructor.name :', userWP.constructor.name);
user.password = 321;
console.log('UserType.prototype', inspect(UserType.prototype));
console.log('UserType.WithoutPassword.prototype', inspect(UserType.WithoutPassword.prototype));
debugger;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment