How to set proxy on constructor function - javascript

I have a constructor function like this:
function a(p){
this.k=12;
this.f = p;
this.t = function(){};
}
Now let say i create a object with this function:
let obj = new a("tf");
I can always do this to check if a new property assigned to object:
obj = new Proxy(obj,{set:()=>{console.log("new property assigned!");return true;}})
//Now if i were to say
obj.property1 = 12
//It will log out "new property assigned!"
But the problem is, that i have to do this for every new object i create with this constructor function.
So what i want to do is whenever i create a new object like this:
let newObj = new a();
I want to set my proxy automatically.
How can i achieve this?

Write a factory function in which you create a new instance of your object while also adds a Proxy to the newly created instance.
function proxyFactory(Class, ...args) {
const instance = new Class(...args);
return new Proxy(instance, {
set: () => {
console.log("new property assigned!");
return true;
}
});
}
And then call the factory function with the class and the arguments you want to apply.
let newObj = proxyFactory(a, "tf");

You could also make a proxy around class, intercept construct calls, and return a proxy with set trap.
const A = new Proxy(a, {
construct(target, args) {
return new Proxy(new target(...args), {
set() {
console.log('new property assigned');
return true
}
})
}
})
const inst = new A('tf')
inst.property = true
function a(p) {
this.k = 12;
this.f = p;
this.t = function() {};
}

You could make a function that wraps around your class. E.g.
const proxyify = (Class, ...args) => {
return new Proxy(new Class(...args), {
set: () => {
console.log('set');
return true;
}
});
}
Usage would then be
function Dog() {
this.type = "Dog";
}
const ProxiedDog = proxify(Dog);

Related

Javascript new keyword

What does it mean when the instance is created in the following way?
somevar = new Person.doSomething()
is this a shortcut to create the instance and call the method , like
person = new Person ()
person.doSomething()
or is it something else?
Thanks in advance.
No, this does not create a new instance of Person and then call a method on it. It creates an instance of whatever Person.doSomething() is. So, in effect, you these two are equivalent:
const Person = {
doSomething: function(foo, bar){
this.foo = foo;
this.bar = bar;
}
}
//create a new instance of `Person.doSomething`
const p1 = new Person.doSomething(1, "one");
//take a reference of `Person.doSomething`
const temp = Person.doSomething;
//create an instance of it
const p2 = new temp(2, "two");
console.log("p1:", p1);
console.log("p1 instanceof Person.doSomething:", p1 instanceof Person.doSomething);
console.log("p2:", p2);
console.log("p2 instanceof Person.doSomething:", p2 instanceof Person.doSomething);
You can only get instances using constructable functions. These are plain functions (declared with the function keyword) and class constructors:
function PlainConstructable(a, b) {
this.foo = a;
this.bar = b;
}
const plainInstance = new PlainConstructable("plain", "instance");
class ClassConstructable {
constructor(a, b) {
this.foo = a;
this.bar = b;
}
}
const classInstance = new ClassConstructable("class", "instance");
console.log(`plainInstance:
instanceof PlainConstructable: ${plainInstance instanceof PlainConstructable}
what it holds: ${JSON.stringify(plainInstance)}`);
console.log(`classInstance:
instanceof ClassConstructable: ${classInstance instanceof ClassConstructable}
what it holds: ${JSON.stringify(classInstance)}`);
Non-constructable are:
arrow functions
shorthand methods in objects or classes
most built-in functions (exceptions are explicitly mentioned in documentation)
const arrowFunction = () => {};
const plainObject = {
shorthandMethod() {}
}
try {
new arrowFunction();
console.log("Constructing arrow function successful.");
} catch(e) {
console.log(
`Cannot construct arrow function
${e}`
)
}
try {
new plainObject.shorthandMethod();
console.log("Constructing shorthand method successful.");
} catch(e) {
console.log(
`Cannot construct shorthand method
${e}`
)
}
try {
new parseInt();
console.log("Constructing built-in successful.");
} catch(e) {
console.log(
`Cannot construct built-in
${e}`
)
}
For more information about constructable functions

How to bind "this" automatically while calling a function?

My example code:
var Person = (function () {
var __sym = Symbol('Person');
class Person {
constructor(name) {
this[__sym] = { name: name };
}
getName() {
let _this = this[__sym];
return _this.name;
}
}
return Person;
}());
var person = new Person('Hermione');
console.log(person.name); // undefined
console.log(person.getName()); // Hermione
In this example, I'd use __sym as a key to assign to the private data.
My question is: How to bind this[__sym] to every method inside the Person class?
My real project:
let Chatwindow = (function () {
let __sym = Symbol('Chatwindow');
let __data = {};
// for typo
let __prop = {
targetUserId: 'targetUserId'
};
__data.init = function (...args) {
let _this = this[__sym];
let options = args[0];
// validating the type of 'options' and the properties...
// just get what I need
_this[__prop.targetUserId] = options[__prop.targetUserId];
(async () => {
let messages = await __data.getMessagesAsync.call(_this);
// my goal:
// let messages = await __data.getMessagesAsync();
})();
};
__data.getMessagesAsync = function () {
let _this = this;
let promise = new Promise(function (done) {
// create model before sending
let model = { [__prop.targetUserId]: _this[__prop.targetUserId] };
// sending...
done();
});
return promise;
};
class Chatwindow {
constructor() {
this[__sym] = {};
}
set init(value) {
return __data.init;
}
get init() {
return (...args) => __data.init.call(this, ...args);
}
}
return Chatwindow;
}());
Everytime I call a method, I have to use call(_this) function to bind the key, like this:
let messages = await __data.getMessagesAsync.call(_this);
After that, inside the getMessagesAsync method, I can assign to the private data using this property.
What I want to achieve: I want to bind all of the methods just one time inside the init method. How can I do that?
Something like this:
__data.getMessagesAsync.oncall = function () {
// bind this with this[__sym]
};
Then,
__data.getMessagesAsync(); // no need to pass anymore
Thank you!
You can use arrow functions, so you will be sure that context (this) will be same every time (this will be pointing to parent this no matter from where arrow function is called)
__data.getMessagesAsync = () => {
let promise = new Promise((done) => {
// create model before sending
let model = { [__prop.targetUserId]: this[__prop.targetUserId] };
// sending...
done();
});
return promise;
}
In javascript, using function_name.bind(o) allows you to create a new function whose context this is bound to the object o.
What you want is to create a new function:
__data.boundMessagesFunction = __data.getMessagesAsync.bind(_this);
Now you can call:
let messages = await __data.boundMessagesFunction();

add a method to a prototype

I have the following code
const humanUtils = {
sayRace: function(){
console.log('Im a '+ this.race);
}
}
function human() {
const human = Object.create(humanUtils);
human.race = 'human';
return human;
}
const manUtils = Object.create(humanUtils);
function man() {
const createMan = new human();
createMan.gender = 'man';
return createMan
}
function woman() {
const createWoman = new human();
createWoman.gender = 'woman';
return createWoman;
}
const mankind = new human();
const adam = new man();
const eve = new woman();
I'd like to add a method to manUtils() which will be only available to man, not to human and woman, such as i can call man.foo().
How can i make the constructor man() to point to manUtils and still accessing humanUtils functions so that i can call adam.sayRace() and adam.foo() inherited from manUtils ?
i don't want to use the new es6 class neither the traditional prototype reassignment (mdn)...if it is possible
Is there a reason for not putting the race property in the humanUtils? If not, just put the race there and you can make the constructor man() to point to manUtils and still access humanUtils' functions by writing
function man() {
return Object.create(manUtils)
}
And then, if you want to add a method to manUtils, simply write manUtils.fancyNewMethod = yourNewMethod
A note on new
In your example it makes no sense to use the new operator to construct mankind, adam and eve. When you write new human, a new object is created (lets call it A for reference) with as prototype human.prototype (which is an empty object, since you don't want to reassign humanUtils to human.prototype) and then human is executed with this bound to A. But inside your human constructor you discard A and instead create your own object using Object.create(humanUtils).
Full example
const humanUtils = {
sayRace() {
console.log('Im a '+ this.race);
},
race: 'human'
}
function human() {
return Object.create(humanUtils);
}
const manUtils = Object.create(humanUtils, {
gender: { value: 'man' }
});
function man() {
return Object.create(manUtils)
}
function woman() {
const createWoman = new human();
createWoman.gender = 'woman';
return createWoman;
}
const mankind = human();
const adam = man();
const eve = woman();
console.log(adam.gender)
adam.sayRace()
console.log('humanUtils isPrototypeOf adam:', humanUtils.isPrototypeOf(adam))
console.log('manUtils isPrototypeOf eve:', manUtils.isPrototypeOf(eve))
manUtils.saySlogan = function() {console.log('men are cool because they have a slogan')}
adam.saySlogan()

In node.js ES6, is it possible to pass in a type and then instantiate it?

In my project I have several classes that look like this:
"use strict";
var exports = module.exports = {};
var SystemsDAO = require('./dao/systems/SystemsDAO.js');
var aop = require('./dbAOPUtils.js');
var Proxy = require('harmony-proxy');
var sqlite3 = require('sqlite3').verbose();
/* Wraps a SystemServiceObject and passes in a constructed
* DAO object as an argument to specified functions. */
exports.SystemsDAOIntercepter = function(obj) {
let handler = {
get(target, propKey, receiver) {
const origMethod = target[propKey];
return function(...args) {
console.log('systemDAOIntercepter: BEGIN');
// Create a reportsdao object and proxy it through an dbSQLiteConnectionIntercepter
// (So we don't have to create it for every single method)
var systemdao = new SystemsDAO('blah');
var proxSystemDAO = aop.dbSQLiteConnectionIntercepter(systemdao, sqlite3.OPEN_READONLY);
args.push(proxSystemDAO);
console.log('propKey: ' + target[propKey]);
let result = null;
result = origMethod.apply(this, args);
console.log('systemsDAOIntercepter: END');
return result;
};
}
};
return new Proxy(obj, handler);
};
Is it possible to pass in a type for an argument so that I only need a single DAOIntercepter class, and not one for each data access object?
I can see the part where I require() the SystemsDAO working for this by passing the file name, but as for instantiation of that class, I can't really see how it would be possible to do that.
Sure - you can pass classes around like any other variable in javascript.
Note that DAOType is provided and instantiated inside the method, now.
"use strict";
var exports = module.exports = {};
var aop = require('./dbAOPUtils.js');
var Proxy = require('harmony-proxy');
var sqlite3 = require('sqlite3').verbose();
/* Wraps a SystemServiceObject and passes in a constructed
* DAO object as an argument to specified functions. */
exports.makeInterceptor = function(DAOType, obj) {
let handler = {
get(target, propKey, receiver) {
const origMethod = target[propKey];
return function(...args) {
console.log('systemDAOIntercepter: BEGIN');
// Create a reportsdao object and proxy it through an dbSQLiteConnectionIntercepter
// (So we don't have to create it for every single method)
var dao = new DAOType('blah');
var proxSystemDAO = aop.dbSQLiteConnectionIntercepter(dao, sqlite3.OPEN_READONLY);
args.push(proxSystemDAO);
console.log('propKey: ' + target[propKey]);
let result = null;
result = origMethod.apply(this, args);
console.log('makeInterceptor: END');
return result;
};
}
};
return new Proxy(obj, handler);
};
I have to admit that I would (personally) prefer to see the class instantiated externally and injected in through the arguments, however, instead of creating it inline.

How to properly derive object with private vars using javascript (prototypal) inheritance

I am new to JavaScript's (prototypal) inheritance and I'm trying to learn more about it.
I am using a simple observer pattern as example, in which I want observable objects to be derived from the 'subject' object. This is what I WANT to do:
function subject()
{
var callbacks = {}
this.register = function(name, callback)
{
callbacks[name] = callback;
}
this.unregister = function(name)
{
delete callbacks[name];
}
var trigger = function()
{
var a = arguments;
var t = this;
$.each(callbacks, function(name, callback)
{
callback.apply(t, a);
});
}
}
list.prototype = new subject()
function list()
{
var items = {}
this.add = function(name, item)
{
items[name] = item;
trigger('add', name);
}
this.remove = function(name)
{
delete items[name];
trigger('remove', name);
}
}
Now when using the code above like below, I run into my first problem:
var l = new list()
l.register('observer1', function() { console.log(this, arguments) });
l.add('item1', 'value1'); // <-- ReferenceError: trigger is not defined, trigger('add', name);
To continue testing I made the trigger function 'public' using this.trigger instead. Running my example again I run into the next problem:
var l = new list()
l.register('observer1', function() { console.log(this, arguments) });
l.add('item1', 'value1'); // <-- output: subject, ["add", "item1"]
The this object is subject, I want it to be list. My third problem occurs when creating another list:
var l2 = new list();
//Don;t register any observers
l2.add('item1', 'value1'); // <-- output: subject, ["add", "item1"]
The callbacks list is shared between the 2 lists.
I've tried similar things with Object.create(new subject()) as well and run into similar problems.
My 3 questions in this are:
Can I have private methods that can be used in derived objects (and
should I even care about having them private or public)?
How can I have the this object I want (without needing to use function.call in the derived object, if possible)?
How can I keep the callbacks list in the base object without it being shared?
An interesting question. As for #1 and #2: let's say you have a function foo:
function foo() {
var _private = 'private var!';
this.access = function () {
return _private;
}
}
access is a so-called privileged method, it's a closure that can access the private variable private.
you can inherit the whole thing by making use of call, like so:
function bar() {
foo.call(this);
}
var b = new bar();
console.log(b.output()); // prints 'private var!'
With the methods apply, call and bind you can establish the context of a function, effectively tamper with the this object. (your #2 question, read here )
Naturally you cannot make use of a totally private method in a derived object. You'd need an accessor method which would defeat the purpose of the original method being private. Having said that, that's the way it works in strongly typed languages too (in java if you mark a method as private not even subclases will be able to access it, it would have to be protected).
As for #3, I cannot think of how to keep callbacks shared and private.
But you can make it a static property for all instances of a function (much like a static property in a lanaguage like java) by simply declaring a function like:
function foo() {
}
add your prototypes which will be assigned to each instance
foo.prototype.bar = // ...
and a static property
foo.callbacks = [];
All instances of foo will share the callbacks property.
You can’t have private methods, and that’s that. It will never work both properly and nicely at the same time, so don’t bother trying to emulate them in JavaScript.
Then all you have to do is call the parent’s constructor in the derived constructor.
function subject()
{
var callbacks = {};
this.register = function(name, callback)
{
callbacks[name] = callback;
};
this.unregister = function(name)
{
delete callbacks[name];
};
this.trigger = function()
{
var a = arguments;
var t = this;
$.each(callbacks, function(name, callback)
{
callback.apply(t, a);
});
};
}
list.prototype = Object.create(subject);
list.prototype.constructor = list;
function list()
{
subject.call(this);
var items = {};
this.add = function(name, item)
{
items[name] = item;
this.trigger('add', name);
};
this.remove = function(name)
{
delete items[name];
this.trigger('remove', name);
};
}
Incorporating Joe's suggestion, this is what I eventually ended up with:
function subject()
{
var callbacks = {}
this.register = function(name, callback)
{
callbacks[name] = callback;
}
this.unregister = function(name)
{
delete callbacks[name];
}
trigger = function()
{
var a = arguments;
var t = this;
$.each(callbacks, function(name, callback)
{
callback.apply(t, a);
});
}
}
//without the following line, 'this' in firefox is 'subject' instead of 'list' (in chrome it is)
list.prototype = new subject()
//without these, 'list' is not an instanceof 'subject'
list.constructor = subject;
list.prototype.constructor = list;
function list(n)
{
this.name = n;
subject.call(this); //as suggested by Joe
var items = {}
this.add = function(name, item)
{
items[name] = item;
trigger.call(this, 'add', name); //no way to do this without using call/apply
}
this.remove = function(name)
{
delete items[name];
trigger.call(this, 'remove', name); //no way to do this without using call/apply
}
this.getitems = function() { return items }
}
//without the following line, 'this' in firefox is 'subject' instead of 'queue'
queue.prototype = new subject()
//without these, 'queue' is not an instanceof 'subject'
queue.constructor = subject;
queue.prototype.constructor = queue;
function queue(n)
{
this.name = n;
subject.call(this); //as suggested by Joe
var items = [];
this.enqueue = function(item)
{
items.push(item);
trigger.call(this, 'enqueue', item); //no way to do this without using call/apply
}
this.dequeue = function()
{
var d = items.shift();
trigger.call(this, 'dequeue', d); //no way to do this without using call/apply
return d;
}
this.getitems = function() { return items }
}
var l1 = new list('l1')
l1.register('observer1', function() { console.log('l1', this, arguments) });
l1.add('item1', 'value1');
// ^ 'l1', list { name = 'l1' ... }, ['add', 'item1']
var l2 = new list('l2')
l2.register('observer2', function() { console.log('l2', this, arguments) });
l2.add('item2', 'value2');
// ^ 'l2', list { name = 'l2' ... }, ['add', 'item2']
var q1 = new queue('q1')
q1.register('observer3', function() { console.log('q1', this, arguments) });
q1.enqueue('item3');
// ^ 'q1', queue { name = 'q1' ... }, ['enqueue', 'item3']
console.log(l1 instanceof list, l1 instanceof subject, l1 instanceof queue);
// ^ true, true, false
console.log(q1 instanceof list, q1 instanceof subject, q1 instanceof queue);
// ^ false, true, true
This ticks all of my boxes (except for the use of call, but I can live with that).
Thanks for all the help,
Mattie
EDIT: appearantly this does not work as expected. creating a new object overwrites the other objects callbacks

Categories