Equality between Proxy and target object - javascript

Javascript's new Proxy feature offers some interesting features for debugging. For example you can "defend" an object by putting it behind a Proxy with a get handler that throws if you access an undefined property. This helps catch typos and other kinds of mistakes.
This could be used something like this:
class Something {
constructor()
{
this.foo = "bar";
allObjects.push(this);
}
};
function defend(o)
{
return new Proxy(o, DebugCheckHandler);
};
let rawSomething = new Something();
let defendedSomething = defend(rawSomething);
Code can be diligently written to only deal in terms of defendedSomething. However in this example, the Something constructor passes this somewhere else (to allObjects). This ends up having the same effect as using both rawSomething and defendedSomething across the codebase.
Problems then arise from the fact the proxy reference does not equal its original reference, since rawSomething !== defendedSomething. For example, allObjects.includes(defendedSomething) will return false if it contains rawSomething, because includes does a strict === check.
Is there a good way to solve this without making too many changes to the code?

Instead of letting the new operator call [[Construct]], which produces a real instance, you can:
Create an object which inherits from the prototype of the constructor.
Use it as the handler of the proxy.
Call the constructor passing the proxy as the this value.
function Something() {
this.foo = "bar";
allObjects.push(this);
}
function defendIntanceOf(C) {
var p = new Proxy(Object.create(C.prototype), DebugCheckHandler);
C.call(p);
return p;
};
let defendedSomething = defendIntanceOf(Something);
Note I used the function syntax instead of the class one in order to be able to use Function.call to call [[Call]] with a custom this value.

Iirc, the only way to influence the this value in a constructor - which is what you need here - is through subclassing. I believe (but can't test) that the following should work:
function Defended() {
return new Proxy(this, DebugCheckHandler);
// ^^^^ will become the subclass instance
}
class Something extends Defended {
// ^^^^^^^^^^^^^^^^ these…
constructor() {
super();
// ^^^^^^^ …should be the only changes necessary
// and `this` is now a Proxy exotic object
this.foo = "bar";
allObjects.push(this);
}
};
let defendedSomething = new Something();

Related

Performance implications of return vs this in a javascript function

What is the difference between following code bits:
function Foo(context) {
let mode;
function setMode(m) {
mode = m;
}
function doStuff() {
if(mode === 'param') {
// ... do stuff with context
} else {
// ... do different stuff with context
}
}
this.setMode = setMode;
this.doStuff = doStuff;
}
vs
function Bar(context) {
let mode;
function setMode(m) {
mode = m;
}
function doStuff() {
if(mode === 'param') {
// ... do stuff with context
} else {
// ... do different stuff with context
}
}
return {
setMode,
doStuff,
}
}
In Foo I use this to 'augment' the new instance of Foo function:
const f = new Foo();
f.setMode('param');
f.doStuff(stuff);
In Bar I return 'new' object with methods each time function Bar is called:
const b = Bar();
b.setMode('parampam');
f.doStuff(stuff);
Are there any benefits (performance? memory usage?) of using one way or another? return vs this?
I am familiar with lexical 'this' scope, and how closure works but I'd like to know if above choice is purely syntactical or it has performance implications?
The performance implications will be trivial: don't worry about those unless this code is getting called a lot, and in that case it's better to benchmark both approaches to see how they're impacting performance in your specific case.
There are a few behavior differences involved. For example, new Foo().constructor points to the Foo function, whereas the object returned by calling Foo() or Bar() without the new keyword doesn't. Also, you can use the instanceof operator to check whether an object is an instance of Foo (meaning whether the object was constructed by calling new Foo()).
So you want to think about how you want users to think about your function.
If you want users to feel like they're creating an instance of a specific class type, and interacting with that class, use the first pattern. The fact that you have functions on that object that act like instance methods makes me think that's what you're going for in this case.
If you want users to feel like the function they're calling is going to procure an object and return it, use the second pattern. In that case, I'd probably rename Bar to something like getBar() or createBar().

Using this or new in JS?

I've got 3 codes :
var control = new Control();
function Control() {
this.doSomethingElse = function() {...}
this.doSomething = function () {
control.doSomethingElse();
}
}
Or
var control = new Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
}
Or
var control = Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
return self;
}
Important : The function is a controller, and just declared once. Then I'm using "control" everywhere in my code...
I was wondering if the control.doSomethingElse() was slow ?
In the end, what is the right thing to do and/or the fastest code in those exemple ?
Thanks !
The first is wrong - an object should never internally use the variable name by which it is known outside. Other code could change that variable to point to something else, breaking this code.
The third is also wrong - when calling Control() without new the assignments to this.foo inside will end up getting attached to the global object (except in strict mode, where there's no implicit this on bare function calls, so the assignment to this.doSomethingElse tries to attach to undefined, causing a runtime error).
That only leaves the second as appropriate, but ultimately it's a question of correctness, not performance.
Do not define methods in constructor - that means defining them every time an instance is created. Use Control.prototype.foo = function() {} instead. Also you do not need to return this if you're using new operator - that's the whole point of new operator.
The recommended approach is this:
function MyClass(param1) {
// Here we're changing the specific instance of an object
this.property1 = param1;
}
// Prototype will be shared with all instances of the object
// any modifications to prototype WILL be shared by all instances
MyClass.prototype.printProperty1 = function() {
console.log(this.property1);
}
var instance = new MyClass("Hello world!");
instance.printProperty1(); // Prints hello world
To understand this code, you need to understand javascript's prototype-based inheritance model. When you create instance of MyClass, you get a new object that inherits any properties present in MyClass.prototype. Read more about it.
Also I wonder:
The function is a controller, and just declared once.
If you're not using this multiple times, you don't need to create something like class. You can do this instead:
var control = {doSomething:function() { ... }};
I assume you are used to Java, where everything must be a class, whether it makes sense or not. Javascript is different, you can also make single objects or functions as you need.

Making `obj.someMethod()` available as `obj()` without preventing `obj` from behaving as a normal instance

To avoid misunderstanding, let's agree on the meaning of certain words first. The following meanings are not universally accepted ones, I only suggest them as a context for this question.
function -- an instance of Function. It has a procedure associated with it.
object -- an instance of any other class. Does not have a procedure associated with it.
procedure -- a block of code that can be executed. In JS procedures can only be found associated with functions.
method -- a function that is stored in a property of another object. Methods execute in their host objects' contexts.
In JavaScript it is common that objects are customized with properties and methods, while functions don't. In other words, if you see this in code:
foo.bar // Accessing a property on an instance
foo.baz() // Calling a method on an instance
then foo is almost certainly an object and not a function.
But technically functions are no different from objects (in fact, functions in JS are considered to be objects, it's just me distinguishing them for clarity).
And if you do this:
const foo = function () { /*...*/ }
foo() // Calling the function's procedure
foo.bar // Accessing a property on the function
foo.baz() // Calling a method on the function
...it will work just fine.
I would like to introduce two more terms so that you can understand what I mean. I'm not trying to alter the rules of JavaScript here, just want to be understood.
function-object -- an function that is used as an object: has its own properties and/or methods.
main method -- the procedure of a function-object itself, as opposed to methods stored as properties on a function-object.
Many JS libraries offer function-objects, for example jQuery and LoDash. I. e. you can do both $() and $.map().
Okay, now to the matter.
I would like to be able to create my own function-objects with the following requirements:
I should be able to use the ES2015 class declaration to describe the class of my function-object. Or at least the way of describing the class should be convenient enough. Imperatively assigning properties and methods to a function is not convenient.
The main method of my function object should execute in the same context as its other methods.
The main method and other methods should be bound to the same instance. For example if I have a main method and a normal method that both do console.log(this.foo), then assigning to myFunctionObject.foo should modify the behavior of both the main mehtod and the other method.
In other words, I want to be able to do this:
class Foo {
constructor () { this.bar = 'Bar'; }
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
...but an instance of Foo should have foo.mainMethod() available simply as foo().
And doing foo.bar = 'Quux' should modify the behavior of both foo() and foo.anotherMethod().
Maybe there's a way to achieve it with class Foo extends Function?
If you don't override anything, new Foo will return an object type, not a function type. You can potentially do
class Foo {
constructor(){
const foo = () => foo.mainMethod();
Object.setPrototypeOf(foo, this);
foo.bar = 'Bar';
return foo;
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
so that new Foo will return a function that has explicitly been set up so that it returns a function with the proper prototype chain configuration. Note that I'm explicitly setting foo.bar instead of this.bar so that hasOwnProperty will still work as expected throughout the code.
You could also work around this by setting it up via a base class, e.g.
class CallableClass {
constructor(callback){
const fn = (...args) => callback(...args);
Object.setPrototypeOf(fn, this);
return fn;
}
}
class Foo extends CallableClass {
constructor(){
super(() => this.mainMethod());
this.bar = 'Bar';
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
I'm writing this in real ES6, but you'll have to change the rest/spread args to a normal function if you want it to work in Node v4. e.g.
const foo = function(){ callback.apply(undefined, arguments); };
The downside to both of these approaches is that they rely on Object.setPrototypeOf, which does not work in IE<=10, so it will depend what support you need. The general understanding is that Object.setPrototypeOf is also very slow, so I'm not sure you have a ton of options here.
The main alternative that ES6 provides for this case would be Proxies, but they are not at all well supported yet.
AFAIK there is no way to add a [[Call]] method to an existing object.
Proxies might seem a potential solution, but the problems are that the proxy object is a different object than the [[ProxyHandler]], and that the [[ProxyHandler]] must already have a [[Call]] method in order to be able to set an "apply" trap.
Therefore, the only viable solution is creating a new function with the desired [[Call]], replace its [[Prototype]], and make the constructor return that function instead of the "real" instance.
class Foo {
constructor () {
var instance = function(){ return instance.mainMethod(); };
Object.setPrototypeOf(instance, Foo.prototype);
return Object.assign(instance, {bar: 'Bar'});
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}

How should you inherit from EventEmitter in node?

I was reading over this small article to understand inheriting from EventEmitter, but I'm a little confused.
He does this:
function Door() {
events.EventEmitter.call(this);
this.open = function() {
this.emit('open');
};
}
Door.prototype.__proto__ = events.EventEmitter.prototype;
https://gist.github.com/chevex/7646362
Why does he manually invoke the EventEmitter constructor with his own constructor's this? Also, why does he set the prototype of his contsructor's prototype to the prototype of EventEmitter? That's super confusing to me.
Then someone in the comments suggested he do this instead, which seemed more elegant:
function Door() {
events.EventEmitter.call(this);
this.open = function () {
this.emit('open');
}
}
util.inherits(Door, events.EventEmitter);
https://gist.github.com/chevex/7646447
This seems WAY cleaner than the other way, though that's probably just because I fail to understand what's going on in the first instance. I would not be surprised if util.inherits is doing the same thing as the first example.
The second one at least makes a little sense to me, but I still don't understand why they don't just do this:
function Door() {
this.open = function () {
this.emit('open');
}
}
Door.prototype = new events.EventEmitter();
https://gist.github.com/chevex/7646524
Can anyone explain to me what the differences between all of these approaches is and why in the first two they invoke .call(this) on the EventEmitter constructor? I omitted that line while trying out the examples and they still worked.
The third example is not generally correct: that creates one single EventEmitter instance for all door instances.
Let's imagine a simple case:
var Foo = function() {
// each Foo instance has a unique id
this.id = Math.random();
}
Foo.prototype.doFoo = function() { console.log("Foo!"); }
Suppose we want to create a Bar constructor that inherits from Foo and adds some new properties. If you follow your final example:
var Bar = function() {
this.something = 5;
}
Bar.prototype = new Foo();
This is wrong because all Bar instance will have the same id property. Instead, we must call the parent constructor for each instance:
var Bar = function() {
Foo.call(this); // set unique `id` on `this`
this.something = 5;
}
Bar.prototype = Object.create(Foo.prototype);
Note that the final line here is the same as Bar.prototype.__proto__ = Foo.prototype; because Object.create creates a new object whose __proto__ is set to the Object.create argument.
Why does he manually invoke the EventEmitter constructor with his own constructor's this?
This is necessary to make sure whatever code is in the EventEmitter constructor function is executed. Some classes might not do anything interesting in the constructor, but others will have important code there, so you should always do this to make sure that code runs the same way it would run if you had just made a new EventEmitter directly with var emitter = new EventEmitter;
In some languages (such as Java) this "constructor chaining" type behavior is implicit, but in JavaScript it must be explicitly done.
Exactly how to set up inheritance in JavaScript comes down to an "it's complicated" answer and others can probably do it more justice than I. There are also several viable variations and people differ on which is preferable. However, FYI the source for util.inherits is here and the best in-depth examination of all the flavors of doing this I have seen is in this video: Douglas Crockford: Advanced JavaScript. Basically, watch that in it's entirety periodically until it sinks in.
Places to look for reference. If you fully understand how all these works, you've mastered it (it still turns my brain into a pretzel at some point along the way)
Backbone's extend helper function (which is Backbone.Model.extend, Backbone.View.extend, etc)
CoffeeScript's class support
node.js's util.extend
function Door() {
events.EventEmitter.call(this);
}
Door.prototype.__proto__ = events.EventEmitter.prototype;
In this case using events.EventEmitter.call(this) is like using super in languages which have one. It's actually can be omitted in simple cases, but it will break domain support on current node version and maybe something else in future versions.
Setting __proto__ just sets up the prototype chain. At can be also done like this:
Door.prototype = Object.create(events.EventEmitter.prototype);
but in this case you also need to set constructor property manually.
util.inherits(Door, events.EventEmitter);
This is the idiomatic way of inheriting in node. So you are better to use this. But what it does is basically the same as above.
function Door() {
}
Door.prototype = new events.EventEmitter();
And this is the WRONG way, don't use it! You will end with having events shared between instances in some versions of node.
The Node v6.3.1 documentation states about util.inherits(constructor, superConstructor):
Usage of util.inherits() is discouraged. Please use the ES6 class and extends keywords to get language level inheritance support. Also note that the two styles are semantically incompatible.
The following code shows how to inherit from EventEmitter with Typescript:
import { EventEmitter } from "events"
class Person extends EventEmitter {
constructor(public name: string) {
super()
}
}
let person = new Person("Bob")
person.on("speak", function (said: string) {
console.log(`${this.name} said: ${said}`)
})
person.emit("speak", "'hello'") // prints "Bob said: 'hello'"
The previous code will transpile into the following ES6 code:
"use strict";
const events = require("events");
class Person extends events.EventEmitter {
constructor(name) {
super();
this.name = name;
}
}
let person = new Person("Bob");
person.on("speak", function (said) { console.log(`${this.name} said: ${said}`); });
person.emit("speak", "'hello'");

Creating a Javascript Object Which Does Nothing

As a somewhat hacky method of disabling functionality, I came up with the idea of using some javascript like this:
//fakefrob.js
var frob = function () {
return {
myFunc: function(){},
myFunc1: function(){},
myFunc2: function(){return 2;},
myFunc3: function(){},
myFunc4: function(){}
};
}();
In this example, the real frob has implementations of these functions. Obviously this is a hack (the functions mostly do nothing or have placeholder return values). If I add foobar to realfrob.js, I must add an empty implementation of foobar to fakefrob.js. Is there a way (ideally without using a library) to write fakefrob.js such that frob.foobar acts like foobar was defined as function(){};, without actually adding foobar to fakefrob.js?
Is there a way (ideally without using a library) to write fakefrob.js such that frob.foobar acts like foobar was defined as function(){};, without actually adding foobar to fakefrob.js?
You mean, a catch-all property, mapped to a no-op function? No, JavaScript doesn't (currently) have catch-all properties at all. (I believe some mechanism for them is being considered, as part of the proxy stuff coming down the pike at some stage.)
If you have access to the real frob in your code, though, your fakefrob can be generated completely automatically:
// Assumes `frob` already exists
(function() {
var mock;
var name;
// Build the mock, with a function for each function
// on the real object.
mock = {};
for (name in frob) {
if (typeof frob[name] === "function") {
mock[name] = function() { };
}
}
// Replace the original
frob = mock;
})();
And of course, if you wanted to copy the non-function properties, you could do that at the same time.
Note that I intentionally did not include hasOwnProperty in the loop above, as I assume you want your mock to include functions even if frob inherits them from a prototype.
If frob inherits some functions and you wanted your mock to exhibit the same hasOwnPropety behavior for them as the original frob, you can get more creative:
// Assumes `frob` already exists
(function() {
var mock;
var mockProto;
var name;
function FakeFrob() {
}
mockProto = FakeFrob.prototype;
// Build the mock, with a function for each function
// on the real object.
mock = new FakeFrob();
for (name in frob) {
if (typeof frob[name] === "function") {
if (frob.hasOwnProperty(name)) {
mock[name] = function() { };
}
else {
mockProto[name] = function() { };
}
}
}
// Replace the original
frob = mock;
})();
Now, if the original frob had its own foo (frob.hasOwnProperty("foo") is true) but an inherited bar (frob.hasOwnProperty("bar") is false), hasOwnProperty on your mock would say exactly the same thing.
As T.J. Crowder suggests, supported browsers can use a proxy object to accomplish this:
var frob = new Proxy({}, {get: function(){return function(){}}})
How this works:
This creates a proxy which intercepts all property getters, replacing the result with an empty function. Normally, a proxy object is used to to intercept and eventually forward calls to our target (here, the target is {}). However, this code blindly returning an empty function, completely ignoring the target.

Categories

Resources