is there any way to influence what console.log gives out custom objects?
I tried to overwrite the customObject.prototype.toString method, that did not work though.
Any ideas?
In node.js, console.log calls util.inspect on each argument without a formatting placeholder. So if you define an inspect(depth, opts) method on your object it will be called to get your custom string representation of the object.
For example:
function Custom(foo) {
this.foo = foo;
}
Custom.prototype.inspect = function(depth, opts) {
return 'foo = ' + this.foo.toUpperCase();
};
var custom = new Custom('bar');
console.log(custom);
Outputs:
foo = BAR
Or using a class:
class Custom {
constructor(foo) {
this.foo = foo;
}
inspect(depth, opts) {
return 'foo = ' + this.foo.toUpperCase();
}
}
var custom = new Custom('bar');
console.log(custom);
The previous answer has been deprecated in newer versions of node. The method one needs to implement now is the symbol [util.inspect.custom].
For example:
const util = require('util');
class Custom {
constructor(foo, bar) {
this.foo = foo;
this.bar = bar;
}
[util.inspect.custom](depth, opts) {
return this.foo + this.bar;
}
}
console.log(new Custom(3, 5)); // Prints '8'
Recent (18) Node.js version has this documentation snippet as an example of how to do this across Node and Browsers:
const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom');
class Password {
constructor(value) {
this.value = value;
}
toString() {
return 'xxxxxxxx';
}
[customInspectSymbol](depth, inspectOptions, inspect) {
return `Password <${this.toString()}>`;
}
}
const password = new Password('r0sebud');
console.log(password);
// Prints Password <xxxxxxxx>
Related
I'm creating a basic class in a Node project, and I want to test it using Jest. I'm getting an error that is implying the use of 'strict' mode in the test, which I want to avoid/fix
~/lib/LogRecord.js
module.exports = class LogRecord {
constructor(level, message, timestamp) {
this.level = level;
this.message = message;
this.timestamp = timestamp ? timestamp : Date.now();
}
get level() {
return this.level;
}
get message() {
return this.message;
}
get timestamp() {
return this.timestamp;
}
}
I'm testing it with this:
let LogRecord = require('../lib/logRecord');
describe('Test LogRecord functionality', () => {
test('LogRecord constructor', () => {
let timestamp = Date.now();
let logRecord = new LogRecord('INFO', 'Test Message', timestamp);
expect(logRecord.level).toBe('INFO');
expect(logRecord.message).toBe('Test Message');
expect(logRecord.timestamp).toBe(timestamp);
});
test('LogRecord is read-only', () => {
let timestamp = Date.now();
let logRecord = new LogRecord('INFO', 'Test Message', timestamp);
logRecord.level = 'WARN'
logRecord.message = 'New Message'
logRecord.timestamp = Date.now();
expect(logRecord.level).toBe('INFO');
expect(logRecord.message).toBe('Test Message');
expect(logRecord.timestamp).toBe(timestamp);
});
});
When I run npm test I get the following error on both of the LogRecord tests:
Test LogRecord functionality › LogRecord constructor
TypeError: Cannot set property level of #<LogRecord> which has only a getter
1 | module.exports = class LogRecord {
2 | constructor(level, message, timestamp) {
> 3 | this.level = level;
| ^
4 | this.message = message;
5 | this.timestamp = timestamp ? timestamp : Date.now();
6 | }
at new LogRecord (lib/logRecord.js:3:9)
at Object.test (test/logRecord.test.js:6:25)
Edit - Working class
const data = new WeakMap();
let levelKey = {id:'level'};
let messageKey = {id:'message'};
let timestampKey = {id:'timestamp'};
module.exports = class LogRecord {
constructor(level, message, timestamp) {
data.set(levelKey, level);
data.set(messageKey, message);
data.set(timestampKey, timestamp ? timestamp : Date.now());
}
get level () {
return data.get(levelKey)
}
get message () {
return data.get(messageKey)
}
get timestamp () {
return data.get(timestampKey)
}
}
Testing is about making sure that your code does what you think it does. Consider the following class:
class Foo {
constructor (bar) {
this._bar = bar;
}
get bar () {
return this._bar;
}
}
Here bar is read-only, there is no way to set the bar property:
let foo = new Foo('a foo');
foo.bar; // 'a foo'
foo.bar = 'am not'; // TypeError!
The modules question isn't really relevant: as Logar linked in the comments class bodies are always strict mode irregardless.
So if you want a property to be read only, you don't need to worry about writing it. Workflow might look something like this:
Write empty class Foo class Foo {} and construct an instance foo = new Foo()
Write test that checks for bar which fails because we have an empty class
Add constructor parameter and getter
Check that test now passes
Add test to ensure that trying to set bar throws expected error*
If you don't want read-only properties you can just add a setter:
class Foo {
constructor (bar) {
this._bar = bar;
}
get bar () {
return this._bar;
}
set bar (value) {
this._bar = value;
}
}
In which case you'd add a test that sets bar and the reads the altered value back out.
* You might be wondering why this test is here when this behavior is guaranteed by the spec and I would argue that the test is necessary since someone could (transparently to the callers) refactor the class to be an old-school constructor and create a vector for bugs:
// post refactor Foo
const Foo = function Foo(bar) {
this.bar = bar; // danger! now writable!
};
Hopefully this sort of thing would be caught by a knowledgable reviewer, but I'd write the test anyways.
Update
If what you want is a guaranteed read-only property that you set in the constructor, here is a recipe for such:
const data = new WeakMap();
module.exports = class Foo () {
constructor (bar) {
data.set(this, bar);
}
get bar () {
return data.get(this);
}
};
Because data is not exported no outside code can change it. Attempting to set the bar property of an instance will throw. This is a bit more complicated that just defining an underscore property with getters and setters, but if it's what you want, well... I know this pattern because I've used it.
Update 2
You only create one weakmap per module, not per class or instance. The weakmap stores a unique data entry keyed to individual instances (i.e. this):
const data = new WeakMap();
module.exports = {
Foo: class Foo () {
constructor (bar) {
data.set(this, bar);
}
get bar () {
return data.get(this);
}
},
Bar: class Bar () {
constructor (prop1, prop2) {
// for multiple props we'll store an object...
data.set(this, { prop2, prop1 });
}
get prop1 () {
// ...and retrieve it and access it's props to return
return data.get(this).prop1;
}
get prop2 () {
return data.get(this).prop2;
}
}
};
Note that setting the props with a getter but no setter will still throw...
// in someotherfile.js
const { Foo } = require('path/to/file/with/foo.js');
const foo = new Foo('imma foo');
foo.bar; // 'imma foo'
foo.bar = 'no not really'; // TypeError!
// you can still set random properties that don't have a getter:
foo.baz = 'I do not throw';
foo.baz; // 'I do not throw'
If you want your properties to be read only after object initialization, you can use Object.freeze in the constructor, and remove your getters :
class LogRecord {
constructor(level, message, timestamp) {
this.level = level;
this.message = message;
this.timestamp = timestamp ? timestamp : Date.now();
Object.freeze(this);
}
}
But this will freeze all of your object's properties. You won't be able to modify, remove, or add any after that. Didn't dive too deep into this so it may have some flaws as well
I'm building a javascript library and I would like to be able to do exactly like the PHP's __get does.
My library has a attributes property which stores each model's attributes. Now, I am force to get an attribute using a .get method. But I would be able to do it with a getter. Let's says that User extends my model class.
let instance = new User({firstname: 'John', lastname: 'Doe'});
console.log(instance.get('firstname')); // gives me 'John'
I want to be able to do instance.firstname which will call the .get method passing 'firstname' as parameter. In PHP you can do it that way : http://php.net/manual/fr/language.oop5.overloading.php#object.get
Is this something possible?
Thank you all
This is easy using ES 2015 classes:
class Foo {
constructor () {
this._bar = null;
}
get bar () {
doStuff();
return this._bar;
}
set bar (val) {
doOtherStuff();
this._bar = val;
return this;
}
};
var foo = new Foo();
foo.bar = 3; // calls setter function
console.log(foo.bar); // calls getter function
here's the (simplified) output from babel:
var Foo = function () {
function Foo() {
this._bar = null;
}
_createClass(Foo, [{
key: "bar",
get: function get() {
doStuff();
return this._bar;
},
set: function set(val) {
doOtherStuff();
this._bar = val;
return this;
}
}]);
return Foo;
}();
Note that this isn't just for classes, any arbitrary object can have these:
var baz = {
get qux() {
// arbitrary code
},
set qux(val) {
// arbitrary code
}
};
Source.
EDIT
What you want is possible but only in native ES 6 environments, as Proxy cannot be polyfilled.
var getter = function(target, property, proxy) {
console.log(`Getting the ${property} property of the obj.`);
return target[property];
};
var setter = function(target, property, value, proxy) {
console.log(`Setting the ${property} property to ${value}.`);
target[property] = value;
};
var emptyObj = {};
var obj = new Proxy(emptyObj, {
get: getter,
set: setter
});
obj.a = 3; // logs 'Setting the a property to 3'
var foo = obj.a; // logs 'Getting the a property of the obj'
Quite simply assign the properties in a loop:
User = function (attrs) {
for (var name in attrs) {
this[name] = attrs[name];
}
}
User.prototype = {
// further methods
}
Using the ES6 class syntax, - I have to admit I do not see the point of writing things this way:
class User {
constructor (attrs) {
for (var name in attrs) {
this[name] = attrs[name];
}
}
// further methods
}
Remember: the second syntax is exactly what happens with the first one, only with some sugar on top.
I am new to Javascript and I want to send parameter via an object.
I also have tried to create my objects, but unfortunately it did not work. Here's the code:
var obj = (function(foo) {
var str = foo;
var bar = function() {
alert(this.str+" Bar");
}
})();
When I call obj('foo').bar();, I want it to produce foo Bar. How to do that?
This should solve your problem:
var obj = function(foo) {
return {
bar: function() {
alert(foo + ' Bar');
}
}
}
obj('foo').bar();
EDIT: You can even use the "Run code snippent" to test it :)
There are tons of solution for your case. I'll provide my favourite one.
var obj = function(foo) {
if (!(this instanceof obj)) {
return new obj(foo);
}
this.str = foo;
}
obj.prototype.bar = function() {
alert(this.str + " Bar");
};
obj('foo').bar();
//or
new obj('foo').bar();
How must a function be 'chained', in order to call this function like this
F('Test').custom_substring(0,1);
You have to return an object that has a method member named custom_substring. One example:
var F = function(){
return {
custom_substring:function(){
console.log('custom substring');
return this;
}
}
}
F('Test')
.custom_substring(0,1)
.custom_substring(0,1)
.custom_substring(0,1);
To create objects you can use constructor functions and prototype, this is a complex subject and explained here.
I would not mess with the String.prototype because that breaks encapsulation.
The following sample provides a chainable custom_substring that does not modify the original object but instead returns a new one. This is similar to how jQuery and other libraries work (and how built-in string operations work) and it helps make for safer and more predictable code.
function F(str) {
return {
toString: function () { return str; },
// You didn't provide an example of what you want custom_substring
// to do, so I'll have it append a "!" to the beginning of the resulting value
// (since I can't think of anything else for it to do)
custom_substring: function (from, to) {
return F("!" + str.substring(from, to));
}
};
}
var s1 = F("Hello everyone");
var s2 = s1.custom_substring(0, 7);
var s3 = s2.custom_substring(0, 5)
.custom_substring(0, 4);
console.log(s1); // Hello everyone
console.log(s2); // !Hello e
console.log(s3); // !!!He
If you really want to create chainloading you need always return this from methods where it's possible.
For example we have some class with some methods:
function Foo() {
this.foo = 'bar';
return this;
}
Foo.prototype = Object.create({
sayFoo: function() {
console.log(this.foo);
return this;
},
getFoo: function() {
return this.foo; // Here you can't make chainload
},
saySmth: function() {
console.log('Something');
return this;
}
});
And we can use this:
var test = new Foo().sayFoo().saySmth().getFoo(); // prints this.foo -> 'Something' -> returns this.foo
console.log(test); // prints out this.foo
This is what I'm doing right now.
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = function() { return x; };
return x;
}
It works but only if foo is called as a function like so
foo();
But what if I want to call it as a normal variable with a value? I could modify the code to be
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = x;
return x;
}
That would allow me to only call it once as a function and after that as a regular variable. But it's still not what I want. Plus it gets complicated if it accidentally gets called as a function again, returning an error.
Is this even possible in JavaScript?
BTW, this is for a Chrome/Firefox extension, so IE compatibility does not matter.
Ended up using toString because getters don't allow me to redefine the whole attribute, a function must be associated with it. And toString has cleaner syntax.
How about using toString?
var foo = function() {
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
}
More about Object-to-Primitive Conversions in JavaScript
EDIT based on comment. Use a singleton (I think it's called):
myObject.prop = (function(){
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
})()
If only Internet Explorer didn't exist, you could use getters and setters as described by John Resig in this blog article:
John Resig: JavaScript Getters and Setters
... They allow you to bind special functions to an object that look like normal object properties, but actually execute hidden functions instead.
Using a function is your best option for now, however the new JavaScript standard (ECMAScript 5th Ed.) which is being implemented now by all major browser vendors, gives you a method to create accessor properties, where you can define a property with a get and set functions that will be internally called, without worrying to treat this properties as functions, e.g.:
var obj = {};
Object.defineProperty(obj, 'foo', {
get: function () { // getter logic
return 'foo!';
},
set: function (value) {
// setter logic
}
});
obj.foo; // "foo!", no function call
This new standard will take some time to be implemented for all browsers, (the IE9 preview version really disappointed me), and I wouldn't recommend you to use it for production, unless you have total control on the environment where your application will be used.
What I think you want is a lazily instantiated variable, which can be implemented like this.
var myProperty = null;
function getMyProperty() {
return (myProperty = myProperty || builder());
}
This is not practical on the web because IE does not support it, but you can look at
https://developer.mozilla.org/en/defineGetter for examples how to do this.
There are a couple ways to do it, here is one example:
var data = {};
data.__defineGetter__("prop",
(function () {
var value = null;
return function () {
if (null == value) {
value = getYourValueHere();
}
return value;
};
})());
and now you can use it like:
var a = data.prop;
var b = data.prop;
I would recommend a variation on ChaosPandion's answer, but with a closure.
var myProperty = (function () {
var innerProperty = null;
return function() {
return (innerProperty = innerProperty || someComplicatedComputationThatMayTakeMoreTime());
};
})();
and then use myProperty() every time you need to access the variable.
You could define a JavaScript getter. From the Apple JavaScript Coding Guidelines:
myObject.__defineGetter__( "myGetter", function() { return this.myVariable; } );
var someVariable = myObject.myGetter;
See John Resig's post, JavaScript Getters and Setters, and the Defining Getters and Setters page at the Mozilla Developer Centre for more information.
I would use explicit lazy evaluation. Here's my implementation of it based on Scheme's take:
var delay, lazy, force, promise, promiseForced, promiseRunning;
(function () {
var getValue = function () {
return this.value;
};
var RUNNING = {};
var DelayThunk = function (nullaryFunc) {
this.value = nullaryFunc;
};
DelayThunk.prototype.toString = function () {
return "[object Promise]";
};
DelayThunk.prototype.force = function () {
if (promiseRunning (this)) {
throw new Error ("Circular forcing of a promise.");
}
var nullaryFunc = this.value;
this.value = RUNNING;
this.value = nullaryFunc ();
this.force = getValue;
return this.value;
};
var LazyThunk = function (nullaryFunc) {
DelayThunk.call (this, nullaryFunc);
};
LazyThunk.prototype = new DelayThunk (null);
LazyThunk.prototype.constructor = LazyThunk;
LazyThunk.prototype.force = function () {
var result = DelayThunk.prototype.force.call (this);
while (result instanceof LazyThunk) {
result = DelayThunk.prototype.force.call (result);
}
return force (result);
};
delay = function (nullaryFunc) {
return new DelayThunk (nullaryFunc);
};
lazy = function (nullaryFunc) {
return new LazyThunk (nullaryFunc);
};
force = function (expr) {
if (promise (expr)) {
return expr.force ();
}
return expr;
};
promise = function (expr) {
return expr instanceof DelayThunk;
};
promiseForced = function (expr) {
return expr.force === getValue || !promise (expr);
};
promiseRunning = function (expr) {
return expr.value === RUNNING || !promise (expr);
};
}) ();
Example Syntax:
var x = lazy (function () { return expression; });
var y = force (x);
var z = delay (function () { return expression; });
var w = force (z);
Note values are stored once evaluated, so repeated forcing will not do extra computations.
Example usage:
function makeThunk (x, y, z) {
return lazy (function () {
// lots of work done here
});
}
var thunk = makeThunk (arg1, arg2, arg3);
if (condition) {
output (force (thunk));
output (force (thunk)); // no extra work done; no extra side effects either
}
You can use the javascript Proxy class for creating such functionality.
var object = {};
var handler = {
resolvers: {},
get ( target, property, proxy ) {
if ( ! target.hasOwnProperty( property ) && this.resolvers.hasOwnProperty( property ) ) {
// execute the getter for the property;
target[ property ] = this.resolvers[ property ]();
}
return target[ property ];
},
set ( target, property, value, receiver ) {
// if the value is function set as a resolver
if ( typeof value === 'function' ) {
this.resolvers[property] = value;
// otherwise set value to target
} else {
target.property = value;
}
},
has ( target, property, receiver ) {
//true when proxy handler has either a resolver or target has a value;
return this.resolvers.hasOwnProperty( property ) || target.hasOwnProperty( property );
}
};
var lazyObject = new Proxy( object, handler );
Now you can use it like this:
'exampleField' in lazyObject; //returns false
lazyObject.exampleField = function(){ return 'my value' }; // add a resolver function
'exampleField' in lazyObject; //returns true
lazyObject.exampleField; //executes your resolver function and returns 'my value'
This example is to demonstrate the working. You can change after your needs.
Here is a fiddle with a demonstration