Run getter in javascript object defined by Object.setProperty()? - node.js

If I create an object property via Object.defineProperty() with a getter/setter method (an accessor descriptor) like:
var myObj = function myObj() {
var myFoo = 'bar';
Object.defineProperty(this, 'foo', {
enumerable: true,
get: function() {
return myFoo;
},
set: function(newValue) {
myFoo = newValue;
}
});
return this;
};
If I do something like var f = new myObj(); console.log(f) in Node, the output is something like:
{ foo: [Getter/Setter] }
console.log(f.foo) gets the proper 'bar' value, but is there a way to indicate that upon logging/inspecting, it should just run the getter and show the value?

First, it's important to understand why this happens. The logging functions don't run getters by design because your getter function could have side effects, whereas the logging function can guarantee that getting the value of a primitive doesn't.
When you pass an object to console.log, it's really just passing it off to the util module's inspect to format into human-readable text. If we look there, we see that the very first thing it does is check the property descriptor, and if the property has a getter, it doesn't run it. We can also see that this behavior is unconditional – there's no option to turn it off.
So to force getters to run, you have two options.
The simplest is to convert your object to a string before handing it off to console.log. Just call JSON.stringify(obj, null, 4), which will produce reasonably human-readable output (but not nearly as nice as util.inspect's). However, you have to take care to ensure that your object doesn't have any circular references and doesn't do something undesired in a toJSON function.
The other option is to implement a inspect function on your object. If util.inspect sees a function called inspect on an object, it will run that function and use its output. Since the output is entirely up to you, it's a much more involved to produce output that looks like what you'd normally get.
I'd probably start by borrowing code from util and stripping out the part about checking for getters.

This behavior is certainly intentional. I know I wouldn't want all the getter functions on an object running whenever I logged that object; that sounds like potential a debugging landmine, where debugging could alter the state of my program.
However, if indeed that is the behavior you want, you can add a new function:
Object.getPrototypeOf(console).logWithGetters = function(obj) {
var output = {};
var propNames = Object.getOwnPropertyNames(obj);
for(var i=0; i<propNames.length; ++i) {
var name = propNames[i];
var prop = Object.getOwnPropertyDescriptor(obj, name);
if(prop.get) {
output[name] = prop.get();
} else {
output[name] = obj[name];
}
}
// set output proto to input proto; does not work in some IE
// this is not necessary, but may sometimes be helpful
output.__proto__ = obj.__proto__;
return output;
}
This allows you to do console.logWithGetters(f) and get the output you want. It searches through an object's properties for getters (checking for the existence of Object.getOwnPropertyDescriptor(obj, propName).get) and runs them. The output for each property is stored in a new object, which is logged.
Note that this is a bit of a hacky implementation, as it doesn't climb the object's prototype chain.

Related

Node.js | Override Setter

I have a class instance (in my case the class is URL), called req_url. URL has a property that has a setter for one of its properties (search) that is implemented in a way that is problematic for me (doesn't just set the given value but does something to it first).
How can I override that setter without creating a class that inherits from URL (and then create a different setter)?
defineProperty doesn't work since it works at the Object level. I want to to do it on that specific type level.
Whenever you have an instance whose setter you want to bypass, calling Object.defineProperty on the instance to set the property does work:
class Foo {
set prop(arg) {
console.log('setter invoked');
}
}
const f = new Foo();
Object.defineProperty(f, 'prop', { value: 'val' });
console.log(f.prop);
It won't affect any object, it'll only affect objects you explicitly call Object.defineProperty with. The collisions with other objects you seem to be worried about won't occur.
Another (stranger) option would be to delete the setter on the prototype, though if the class is used elsewhere, outside of your code, it could cause problems:
class Foo {
set prop(arg) {
console.log('setter invoked');
}
}
delete Foo.prototype.prop;
const f = new Foo();
f.prop = 'val';
console.log(f.prop);

How to observe all object property changes?

For arrays I know you can do something like this:
function() {
}.observes("array.#each")
What I did was convert the object into an array and observe the properties with a #each, but is there a better way to observe object all property changes without converting it into an array?
You can observe isDirty to see if any of the object's values have been modified since last save (if you are using Ember Data).
Alternatively you can pass a comma separated list of properties to observes. This might be long if you have a lot of properties on your object, but will work.
A third approach could be to override setUnknownProperty() and set a property, a 'dirty flag' (or perform any action you may want in there.
There's also an old SO post that gives the following answer:
App.WatchedObject = Ember.Object.extend({
firstProp: null,
secondProp: "bar",
init: function(){
this._super();
var self = this;
Ember.keys(this).forEach(function(key){
if(Ember.typeOf(self.get(key)) !== 'function'){
self.addObserver(key, function(){
console.log(self.get(key));
});
}
});
}
});
You could probably split this out into a Mixin to keep your code DRY.
probably you could create something like a blabbermouth mixin and override the set method to get notified of property changes:
App.BlabbermouthMixin = Ember.Mixin.create({
set: function(keyName, value) {
this.set('updatedProperty', keyName);
this._super(keyName, value);
}
});
and observe the updatedProperty property?
You can get a list of properties in an object and apply them to a new property:
attrs = Ember.keys(observedObject);
var c = Ember.computed(function() {
// Do stuff when something changes
})
Ember.defineProperty(target, propertyName, c.property.apply(c, attrs));
Here is a working jsbin. Creating an observer instead of a property should be possible using a similar approach.

How to implement inheritance in Node.JS

How do we use 'inheritance' in Node.JS? I heard that prototype is similar to interfaces in java. But I have no idea how to use it!
Although there are various ways of performing inheritance and OO in javascript, in Node.js you would typically use the built in util.inherits function to create a constructor which inherits from another.
See http://book.mixu.net/ch6.html for a good discussion on this subject.
for example:
var util = require("util");
var events = require("events");
function MyOwnClass() {
// ... your code.
}
util.inherits(MyOwnClass, events.EventEmitter);
Creating an object constructor in pure JS:
They're just functions like any other JS function but invoked with the new keyword.
function Constructor(){ //constructors are typically capitalized
this.public = function(){ alert(private); }
var private = "Untouchable outside of this func scope.";
}
Constructor.static = function(){ alert('Callable as "Constructor.static()"'); }
var instance = new Constructor();
Inheritance:
function SubConstructor(){
this.anotherMethod(){ alert('nothing special'); }
}
function SubConstructor.prototype = new Constructor();
var instance = new SubConstructor();
instance.public(); //alerts that private string
The key difference is that prototypal inheritance comes from objects, rather than the things that build them.
One disadvantage is that there's no pretty way to write something that makes inheritance of instance vars like private possible.
The whopping gigantor mega-advantage, however, is that we can mess with the prototype without impacting the super constructor, changing a method or property for every object even after they've been built. This is rarely done in practice in higher-level code since it would make for an awfully confusing API but it can be handy for under-the-hood type stuff where you might want to share a changing value across a set of instances without just making it global.
The reason we get this post-instantiated behavior is because JS inheritance actually operates on a lookup process where any method call runs up the chain of instances and their constructor prototype properties until it finds the method called or quits. This can actually get slow if you go absolutely insane with cascading inheritance (which is widely regarded as an anti-pattern anyway).
I don't actually hit prototype specifically for inheritacne a lot myself, instead preferring to build up objects via a more composited approach but it's very handy when you need it and offers a lot of less obvious utility. For instance when you have an object that would be useful to you if only one property were different, but you don't want to touch the original.
var originInstance = {
originValue:'only on origin',
theOneProperty:'that would make this old object useful if it were different'
}
function Pseudoclone(){
this.theOneProperty = "which is now this value";
}
Pseudoclone.prototype = originInstance;
var newInstance = new Psuedoclone();
//accesses originInstance.originValue but its own theOneProperty
There are more modern convenience methods like Object.create but only function constructors give you the option to encapsulate private/instance vars so I tend to favor them since 9 times out of 10 anything not requiring encapsulation will just be an object literal anyway.
Overriding and Call Object Order:
( function Constructor(){
var private = "public referencing private";
this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
instance.myMethod = function(){ alert(private); }
instance.myMethod();//"undefined"
Note: the parens around the constructor allow it to be defined and evaluated in one spot so I could treat it like an object on the same line.
myMethod is alerting "undefined" because an externally overwritten method is defined outside of the constructor's closure which is what effective makes internal vars private-like. So you can replace the method but you won't have access to what it did.
Now let's do some commenting.
( function Constructor(){
var private = "public referencing private";
this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
//instance.myMethod = function(){ alert(private); }
instance.myMethod();//"public referencing private"
and...
( function Constructor(){
var private = "public referencing private";
//this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
//instance.myMethod = function(){ alert(private); }
instance.myMethod();//"prototype"
Note that prototype methods also don't have access to that internal private var for the same reason. It's all about whether something was defined in the constructor itself. Note that params passed to the constructor will also effectively be private instance vars which can be handy for doing things like overriding a set of default options.
Couple More Details
It's actually not necessary to use parens when invoking with new unless you have required parameters but I tend to leave them in out of habit (it works to think of them as functions that fire and then leave an object representing the scope of that firing behind) and figured it would be less alien to a Java dev than new Constructor;
Also, with any constructor that requires params, I like to add default values internally with something like:
var param = param || '';
That way you can pass the constructor into convenience methods like Node's util.inherit without undefined values breaking things for you.
Params are also effectively private persistent instance vars just like any var defined in a constructor.
Oh and object literals (objects defined with { key:'value' }) are probably best thought of as roughly equivalent to this:
var instance = new Object();
instance.key = 'value';
With a little help from Coffeescript, we can achieve it much easier.
For e.g.: to extend a class:
class Animal
constructor: (#name) ->
alive: ->
false
class Parrot extends Animal
constructor: ->
super("Parrot")
dead: ->
not #alive()
Static property:
class Animal
#find: (name) ->
Animal.find("Parrot")
Instance property:
class Animal
price: 5
sell: (customer) ->
animal = new Animal
animal.sell(new Customer)
I just take the sample code Classes in CoffeeScript. You can learn more about CoffeeScript at its official site: http://coffeescript.org/

How to add context helper to Dust.js base on server and client

I'm working with Dust.js and Node/Express. Dust.js documents the context helpers functions, where the helper is embedded in the model data as a function. I am adding such a function in my JSON data model at the server, but the JSON response to the browser doesn't have the function property (i.e. from the below model, prop1 and prop2 are returned but the helper property is not.
/* JSON data */
model: {
prop1: "somestring",
prop2: "someotherstring",
helper: function (chunk, context, bodies) {
/* I help, then return a chunk */
}
/* more JSON data */
I see that JSON.stringify (called from response.json()) is removing the function property. Not sure I can avoid using JSON.stringify so will need an alternative method of sharing this helper function between server/client. There probably is a way to add the helper functions to the dust base on both server and client. That's what I'm looking for. Since the Dust docs are sparse, this is not documented. Also, I can't find any code snippets that demonstrate this.
Thanks for any help.
send your helpers in a separate file - define them in a base context in dust like so:
base = dust.makeBase({foo:function(){ code goes here }})
then everytime you call your templates, do something like this:
dust.render("index", base.push({baz: "bar"}), function(err, out) {
console.log(out);
});
what this basically does is it merges your template's context into base, which is like the 'global' context. don't worry too much about mucking up base if you push too much - everytime you push, base recreates a new context with the context you supplied AND the global context - the helpers and whatever variables you defined when you called makeBase.
hope this helps
If you want stringify to preserve functions you can use the following code.
JSON.stringify(model, function (key, value) {
if (typeof(value) === 'function') {
return value.toString();
} else {
return value;
}
});
This probably doesn't do what you want though. You most likely need to redefine the function on the client or use a technology like nowjs.

How to have a typed random-access read-only array structure

Still finding my feet with Haxe and am looking for way to have a array-like read-only collection that I can specify a type for at compile time
So ideally I need something like the following:
var collection:Collection<ItemType>;
var item:ItemType = collection[3];//or
var other:ItemType = collection.getAt(3);
//also, it would be good if it was iterable
for (item in collection)
{
//stuff
}
So, exactly like an Array, but read only. Would anybody be able to give me a few pointers, please.
Many thanks
Well, you can't have read-only array access as such, but you can do it with methods:
class ReadonlyArray<T> {
var source:Array<T>;
public function new(source) this.source = source
inline function get(index) return source[index]
inline function iterator() return index.iterator()
}
The overhead should be barely noticeable.

Resources