function object with public static properties - javascript

So I know I can add public properties to functions directly like this.
const print = function (string) {
console.log(string);
};
print.uppercase = function (string) {
print(string.toUpperCase());
};
print("apple"); // apple
print.uppercase("apple"); // APPLE
But I always follow this pattern when I make objects.
const object = function () {
let field;
const getField = function () {
return field;
};
const setField = function (_field) {
field = _field;
};
return Object.freeze({
getField,
setField
});
};
Is it possible to make function objects with public properties while sticking to this pattern? Without using this?
const factory = function () {
const generic = function () {};
const specific = function () {};
return Object.freeze({
// DO SOMETHING HERE SO THAT
});
};
// factory() invokes the generic function, and
// factory.specific() invokes the specific function

I think you are looking for
generic.specific = specific;
Object.freeze(generic);
return generic;
or for short,
return Object.freeze(Object.assign(generic, {
specific,
}));

Related

How to achieve privacy for value saved in `this` in constructor function?

What options do I have to achieve privacy on values I need to save in this in a constructor function? For example, a simple Stack implementation:
function Stack(){
this._stack = {}
this._counter = 0
}
Stack.prototype.push = function (item){
this._stack[this._counter++] = item
return this
}
Stack.prototype.pop = function (){
Reflect.deleteProperty(this._stack, --this._counter);
return this
}
Stack.prototype.peek = function (){
return this._stack[this._counter - 1]
}
Stack.prototype.length = function (){
return Object.values(this._stack).length
}
If these methods are not defined as prototype methods, I can easily private them like this:
function Stack(){
let _stack = {}
let _counter = 0
this.push = function (item){
_stack[_counter++] = item
return this
}
this.pop = function (){
Reflect.deleteProperty(_stack, --_counter);
return this
}
this.peek = function (){
return _stack[_counter - 1]
}
this.length = function (){
return Object.values(_stack).length
}
}
This way _stack and _counter are not exposed, but then these methods are not on prototype chain.
Is it possible to achieve privacy, while the protected values are saved in this?
Here is an example of using private fields. You can make them static with the static keyword, but that is not necessary in this example.
class test {
#lol = 29;
#mas = 15;
constructor() {
this.#lol++;
this.#mas--;
return {
value: this.#lol - this.#mas
};
}
};
console.log(new test().value); // --> 16
MDN provides an example of private properties in their Keyed collections guide.
WeakMap object
The WeakMap object is a collection of key/value pairs in which
the keys are objects only and the values can be arbitrary values.
The object references in the keys are held weakly, meaning that they
are a target of garbage collection (GC) if there is no other reference
to the object anymore. The WeakMap API is the same as the Map API.
One difference to Map objects is that WeakMap keys are not
enumerable (i.e., there is no method giving you a list of the keys).
If they were, the list would depend on the state of garbage
collection, introducing non-determinism.
For more information and example code, see also "Why WeakMap?" on
the WeakMap reference page.
One use case of WeakMap objects is to store private data for an
object, or to hide implementation details. The following example is
from Nick Fitzgerald's blog post "Hiding Implementation Details with
ECMAScript 6 WeakMaps". The private data and methods belong inside
the object and are stored in the privates WeakMap object.
Everything exposed on the instance and prototype is public; everything
else is inaccessible from the outside world because privates is
not exported from the module.
const privates = new WeakMap();
function Public() {
const me = {
// Private data goes here
};
privates.set(this, me);
}
Public.prototype.method = function () {
const me = privates.get(this);
// Do stuff with private data in `me`...
};
module.exports = Public;
Applied to your scenario this could look like this:
const Stack = (function () {
const privates = new WeakMap();
function Stack() {
privates.set(this, { stack: {}, counter: 0 });
}
Stack.prototype.push = function (item) {
const _ = privates.get(this);
_.stack[_.counter++] = item;
return this;
};
Stack.prototype.pop = function () {
const _ = privates.get(this);
Reflect.deleteProperty(_.stack, --_.counter);
return this;
};
Stack.prototype.peek = function () {
const _ = privates.get(this);
return _.stack[_.counter - 1];
};
Stack.prototype.length = function () {
const _ = privates.get(this);
return Object.values(_.stack).length;
};
return Stack;
})();
This answer does not create private properties. However if the intent of the question is to prevent a user from accidentally accessing "private" properties or to prevent property conflict you can use symbols.
A property conflict happens when your function expects property A, while a library (or any other code) also expects property A but for another purpose.
const Stack = (function () {
const stack = Symbol("_stack");
const counter = Symbol("_counter");
function Stack() {
this[stack] = {};
this[counter] = 0;
}
Stack.prototype.push = function (item) {
this[stack][this[counter]++] = item;
return this;
};
Stack.prototype.pop = function () {
Reflect.deleteProperty(this[stack], --this[counter]);
return this;
};
Stack.prototype.peek = function () {
return this[stack][this[counter] - 1];
};
Stack.prototype.length = function () {
return Object.values(this[stack]).length;
};
return Stack;
})();
The above code does not prevent a user from accessing the properties, but makes it somewhat hard. You could still access them using the following code:
const stack = new Stack();
const [_stack, _counter] = Object.getOwnPropertySymbols(stack);
stack[_stack] // gives access to the stack
stack[_counter] // gives access to the counter
Symbol properties are excluded from a lot of common functions like Object.keys(), Object.values(), Object.entries(), and also from for...in loops.
I created a function that has access to private data and returns a function with a closure containing methods for working with them (keeps everything in one place) external functions serve only as a kind of pointers to the internal functions of the provider.
class Stack{
constructor(){
this.provider = this.provider('init', this)
}
provider(type, args){
const state = {}
if (type === 'init'){
state._stack = [];
state._counter = 0;
state.this = args;
}
return function (type, args) {
switch(type){
case 'push':
return _push(args)
case 'pop':
return _pop()
case 'peek':
return _peek()
case 'length':
return _length()
}
function _push(item){
state._stack.push(item)
return state.this
}
function _pop(){
const item = state._stack.pop()
console.log(item)
return state.this
}
function _peek(){
return state._stack[state._stack.length-1]
}
function _length(){
return Object.values(state._stack).length
}
}
}
push(item){
return this.provider('push', item)
}
pop(){
return this.provider('pop')
}
peek(){
return this.provider('peek')
}
length(){
return this.provider('length')
}
}
tests:
s = new Stack();
g = new Stack();
s.push(1).push(2).push(3)
console.log('length s:', s.length()) // 3
s.pop(/* 3 */).pop(/* 2*/)
console.log(s.peek())
s.pop(/* 1 */)
console.log('length s:', s.length()) // 0
g.push('a').push('b').push('c').pop(/* c */).push('d')
g.pop(/* d */)
console.log('g.peek()', g.peek(), /* b */)
g.pop(/* b */)
g.pop(/* a */)
console.log('length g:', g.length()) // 0

Javascript bind Function Implementation

I want to Create Polyfill for bind function of javascript for the browser which does not support bind function. Anyone, please tell how bind function is implemented in javascript.
In its simplest form, bind is just a wrapper for apply:
function bind(fn, thisObj) {
return function() {
return fn.apply(thisObj, arguments);
}
}
Implemented the basic functionality of bind by using apply.
I called this method myBind, added it to the function prototype so that it's accessible by any function:
Function Implementation
Function.prototype.myBind = function() {
const callerFunction = this;
const [thisContext, ...args] = arguments;
return function() {
return callerFunction.apply(thisContext, args);
}
}
Usage:
Can be used as a native bind function taking in the context and arguments.
function testMyBind(favColor) {
console.log(this.name, favColor); // Test, pink
}
const user = {
name: 'Test'
}
const bindedFunction = testMyBind.myBind(user, 'pink');
bindedFunction();
To keep things simple, while using the modern JavaScript:
Function.prototype.bind = function () {
return () => this.call(...arguments);
};
That's all there is to it.
Implemented the basic functionality using apply. Both bind function and bound function can accept arguments.
Function.prototype.bindPolyfill = function (obj, ...args) {
const func = this;
return function (...newArgs) {
return func.apply(obj, args.concat(newArgs));
};
};
Usage:
const employee = { id: '2'};
const getEmployee = function(name, dept){
console.log(this.id, name, dept);
};
const employee2 = getEmployee.bindPolyfill(employee, 'test');
employee2('Sales');
Function.prototype.bindPolyfill = function (newThis, ...args) {
return (...newArgs) => {
return this.apply(newThis, [...args, ...newArgs]);
};
};
// Usage
const employee = { id: '2' };
const getEmployee = function (name, dept) {
console.log(this.id, name, dept);
};
const employee2 = getEmployee.bindPolyfill(employee, 'test');
employee2('Sales'); // 2 test Sales
Function.prototype.customBind = function(ctx, ...args) {
const fn = this;
return function() {
return fn.apply(ctx, args);
}
}
A simple solution

Execute "static" method of a parent of a constructor accessed from a constructor array in Javascript

Phew, even the question was hard to write. Here's the problem: I have a "game", more like a random simulator, which needs to choose a random action from an array of actions, like this one:
actions = [ Action1, Action2, Action3 ]
I have actions written as classes inheriting from the Action parent class:
function Action() {
this.targets = [];
this.used = [];
this.execute = function(player) {
doStuff();
return whatever;
};
}
//btw the below I've seen in a JS OOP tutorial but it doesn't work and I have to implement init() in every child action
Action.init = function(player) {
var a = new this.constructor();
return a.execute(player);
};
Action.checkRequirements = function() {
return true;
};
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1 {
this.execute = function(player) {
doStuff();
return whatever;
}
}
Action1.init = function(player) {
var a = new Action1();
return a.execute(player);
}
So what I'm doing to execute an action and get its results is var foo = actions.getRandomVal().init(); (getRandomVal is a simple custom script that returns a random value from the array) It works well, creates the object instance which properly inherits all properties and methods, executes the exec() method and returns its results... but now I have a checkRequirements() method which I want to implement in like 10% of the 100+ actions I wish to do, and I want it to simply be inherited from the Action class so that when it is not implemented in the child class it simply returns true and I don't have an idea how. If I do var a = actions.getRandomVal(); and then a.checkRequirements(); it throws an exception that a.checkRequirements is not a function.
PS: this is a relatively small non-profit project for a (large) group of friends, I don't need it to work in every browser, it needs to work in Chrome and I can just tell them to use Chrome for it.
Since you only need to work with Chrome, I'd suggest to use ES6 class syntax which does all the inheritance properly, without the chance to mess up. This includes your Action1 constructor to inherit properties ("static class members") from the Action constructor as you'd expect.
class Action {
constructor() {
this.targets = [];
this.used = [];
}
execute(player) {
doStuff();
return whatever;
}
static init(player) {
var a = new this(); // no .constructor
return a.execute(player);
}
static checkRequirements() {
return true;
}
}
class Action1 {
execute(player) {
doOtherStuff();
return whateverelse;
}
}
It looks to me like you're calling checkRequirements() on an instance:
a.checkRequirements();
But it's implemented statically:
Action.checkRequirements = function() {
return true;
};
You probably want to bind this function to the prototype, so change the code above to this:
Action.prototype.checkRequirements = function() {
return true;
};
Then when you want to override this in a derived type, like Action1, you can do this:
Action1.prototype.checkRequirements = function () {
return (whatever);
}
As per comments, my guess is you want something like this...
// base Action type providing basic implementation
// Wrapped in an IIFE to prevent global scope pollution
// All functions are prototype bound to allow prototypical inheritance.
var Action = (function () {
function Action() {
this.targets = [];
this.used = [];
};
Action.prototype.doStuff = function () {
return;
}
Action.prototype.execute = function (player) {
this.doStuff();
return "whatever";
}
Action.prototype.checkRequirements = function () {
return "foo";
}
return Action;
})();
var Action1 = (function () {
Action1.prototype = new Action();
Action1.prototype.constructor = Action1;
function Action1() {
}
Action1.prototype.checkRequirements = function () {
// Super call
return Action.prototype.checkRequirements.call(this);
}
return Action1;
})();
var Action2 = (function () {
Action2.prototype = new Action();
Action2.prototype.constructor = Action2;
function Action2() {
}
Action2.prototype.checkRequirements = function () {
return "bar";
}
return Action2;
})();
// Set up array.
var array = [Action1, Action2];
// Create instances (this is where you would pick at random)
var a1 = new array[0]();
var a2 = new array[1]();
// var aofn = new array[rnd]();
// Tests
alert(a1.checkRequirements()); // Should "foo" because it called super (Action).
alert(a2.checkRequirements()); // Should "bar" because it's overridden.
Check it out on TypeScript Playground

Using object from different module

I've the following code which is parse object and and provide getters to it like following and this is working,The problem is that I want to access to this object from different module and avoid the parsing again ,how can I do that without define global var?
var ymlParser = require('yamljs');
function ymlParse(src) {
if (!(this instanceof ymlParse)) return new ymlParse(src);
this.data = ymlParser.parse(src);
}
ymlParse.prototype = {
getA: function () {
return this.data.default_A;
},
getB: function () {
return this.data._B;
}
};
module.exports = ymlParse;
Lets say I want to access to A from module A and B from module B,how can I do that without sending the src again when I call to getB since when I call to getA I already pass the src...
You can use Memoization pattern - http://addyosmani.com/blog/faster-javascript-memoization/. The one issue with implementation in others answers is not hashing the arguments. So you should have something like this:
var ymlParser = require('yamljs');
function ymlParse(src) {
var hash = JSON.stringify(src);
if (!(this instanceof ymlParse)) return new ymlParse(src);
if (this.cache[hash]) {
this.data = this.cache[hash];
} else {
this.data = ymlParser.parse(src);
this.cache[hash] = this.data;
}
}
ymlParse.prototype = {
cache: {},
getA: function () {
return this.data.default_A;
},
getB: function () {
return this.data._B;
}
};
module.exports = ymlParse;
Take a closer look to JSON.stringify method. You must implement hashing algorithm here that will be associate hash with src data as unique identifier. Usually is JSON.stringify but you can use your own.
Or another solution in functional style:
var _ = require('lodash');
var ymlParser = require('yamljs');
function ymlParse(src) {
var result = ymlParser.parse(src);
return {
getA: function() {
return result.default_A;
},
getB: function() {
return result._B;
}
};
}
module.exports = _.memoize(ymlParse);
Usage the same, you just call exported function as usual function.
You can make caching in your ymlParse class (it's designed like class, isn't it?).
Just store src objects and results of parsing. If ymlParse will be executed with cached src just return stored result without parsing.
Try to change your code like this:
var ymlParser = require('yamljs');
function ymlParse(src) {
if (!(this instanceof ymlParse)) return new ymlParse(src);
if (this.cache[src]) {
this.data = this.cache[src];
} else {
this.data = ymlParser.parse(src);
this.cache[src] = this.data;
}
}
ymlParse.prototype = {
cache: {},
getA: function () {
return this.data.default_A;
},
getB: function () {
return this.data._B;
}
};
module.exports = ymlParse;
Notice that I'm not using deep copy of this.data object. If it's not read-only it may cause some problems.

Extend the properties returned by a function?

I'm a JS beginner. I have defined a function on my Backbone model as follows.
myFunction: function () {
return {
firstAttr: this.model.get('value-attribute')
};
}
It is available to me as this.myFunction.
From somewhere else in the code, I want to extend this.myFunction to return another attribute. In other words, I'd like it to return a dict with two attributes: { firstAttr: 'something', secondAttr: true }.
How can I do this?
I've tried:
this.myFunction().secondAttr = true;
but I know that's the wrong thing to do.
Assuming your model prototype looks like
var MyModel = Backbone.Model.extend({
myFunction: function () {
return {
// I assume you work directly on a model
// the principle would be the same with a wrapper object
firstAttr: this.get('value-attribute')
};
}
});
you can either mask your method on a model by model basis like this:
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
m.myFunction = function () {
var res = MyModel.prototype.myFunction.call(this);
res.secondAttr = true;
return res;
};
console.log(m.myFunction());
See http://jsfiddle.net/V8zt2/ for a demo
Or dynamically modify your prototype to alter all instances :
var f = MyModel.prototype.myFunction;
MyModel.prototype.myFunction = function () {
var res = f.call(this);
res.secondAttr = true;
return res;
};
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
http://jsfiddle.net/V8zt2/1/
How about modifying your myFunction to :
myFunction : function () {
var i,
obj = {};
for (i=0; i< arguments.length;i++){
obj['attribute'+(i+1)] = this.model.get(arguments[i]);
}
return obj;
}
This way you can send keys of model, that you want to be in the returned object as arguments to myFunction.

Categories

Resources