In JavaScript you can extend the functionality of an object with prototype.
Person.prototype.fullName = function () {
return this.first + this.last;
};
I run into scenarios a lot where I need to process something on an array of specific objects. These are cases where it would be nice for the functionality to be linked to that object type, as opposed to just passing as an array parameter. I am aware that it is unadvised to extend the JavaScript Array.
Is there an equivalent standard to extend the functionality of an array of objects? Here is a pseudo-example of what I mean:
Person(Array).prototype.groupByAges = function () {
// logic here that would group by ages
// { '0-15': [person, person], '16-18': [person, person], etc. }
return list;
};
// could be used like this
const list = persons.groupByAges();
What I have tried:
writing functions like getAgeGroupsByPerson(arr) which end up cluttering code
JQuery.grep() and JavaScript arr.map() which help but does not link the functionality to that specific object type.
Note: I realize that there may be better ways to logically solve the specific age grouping problem that I have described. It is just an example to demonstrate my point. Thank you.
I see two different approaches that would satisfy your requirements
1) Write a class that extends Array and stick your array in there
class MyArray extends Array {
groupByAge() {
console.log(this);
}
}
let a = MyArray.from([1,2,3]);
a.groupByAge();
2) Write a normal function that takes an array of your objects and does work on it.
function groupByAge(array) {
console.log(this);
}
There is more work than payoff to try to extend a new Array function IMO than doing both of the above. If JS classes isn't something you can utilize then I'd suggest going for the function and just call that "everywhere".
Upside to both approaches is that they are quite easily testable and that's something that we want.
You can decorate your arrays
let decorate = (array) => {
array.groupByAges = function() {
console.log(`Grouping = ${this}`);
}
return array;
}
decorate([1,2,3]).groupByAges();
Related
I am trying to understand the ways of using functional style in JavaScript in practice. I've created a simple set of functions to process a string, but I feel I am doing it conceptually wrong because it looks just like imperative style, even though I don't mutate input and don't change state of the app inside the functions.
Here is how it looks:
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
var outputLine = LineParser().formatSpaces(inputLine);
// 'A line with multiple spaces'
outputLine = LineParser().capitalize(outputLine);
// 'A Line With Multiple Spaces'
outputLine = LineParser().formatSomethingElse(outputLine);
// Some more formatting, then do further processing with outputLine
If I run the sequence using callbacks, it is going to become an ugly set of nested callbacks really quickly when I have, say, 10 simple processing functions.
If I add methods chaining, the idea of prototype methods looks against functional style too, because functions in the chain will depend on previous state, not only on the input they get.
What should I do to make it look nicer in a functional style?
Update: After deeper research I found topic named Function Composition. It seems to be a proper solution to the problem and is one of the basic things from the functional world.
Here is the function I use to compose multiple functions into one:
var compose = function () {
var funcs = arguments;
return function () {
var args = arguments;
for (var i = funcs.length; i-- > 0;) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
Then I do a composition:
var composedFunction = compose(func1, func2, ..., funcn)
Which run from the right to left and all works just fine.
You lineparser seems to have methods like formatSpaces, capitalize and formatSomethingElse. The easiest thing you could do is to make all those methods to return this, so that you can chain those methods like so:
var outputline = LineParser.formatSpaces(inputLine).capitalize().formatSomethingElse()
Though by the looks of it, all of the methods require some string as a parameter, so you might have to make some implementation changes such as saving the string in a private variable if given and pullin it from the variable if no parameters are given.
Remark about your Edit. The function compose is very functional in the principle but not in its implementation. Indeed, the function mutates some variables (e.g., i and args) and is therefore not fully functional.
To avoid using these mutating variables, you could possibly define compose recursively. Another solution ould be to rely on third-party functional library, such as underscore-js for example (http://underscorejs.org/), which already defines a composition function.
Additional (obvious) remark: to make your code functional with compose, the functions func1, func2,... that are composed, should not mutate their arguments.
If you want asynchronous programming but you don't like nested callbacks, have you considered the async lib ?
You could have something like this :
var LineParser = require('../modules/LineParser');
var inputLine = 'A line with multiple spaces';
async.waterfall([
function(callback) {
var result = LineParser().formatSpaces(inputLine);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().capitalize(arg1);
callback(null, result);
},
function(arg1, callback) {
var result = LineParser().formatSomethingElse(arg1);
callback(null, result);
}
], function (err, result) {
// retrieve the final string
});
which can be turned into something useful if you modify your LineParser methods into asynchronous methods (otherwise it will only make your 3 lines heavier)
Functional style, that is, pure functional style that we see in Lisp etc. looks like this:
var outputline = formatSomethingElse(capitalize(formatSpaces(inputline)));
Often, for readability it would be formatted as:
var outputline = formatSomethingElse(
capitalize(
formatSpaces(inputline)
)
);
Any other form is not functional style. Functional style are a bit like Reverse Polish Notation in that the stated operation should be read in reverse. Indeed, RPN is itself a functional programming syntax (as embodied by Forth).
There is a style that has a similar look and feel to the functional style: method chaining:
var outputline = LineParser(inputline)
.formatSpaces()
.capitalize()
.formatSomethingElse()
.toString();
Unlike functional style, method chaining is read in order.
While the most famous chaining library, jQuery, mutates the state of the object it's not really necessary to do that. Take for example the following simple implementation of LineParser:
function LineParser (text) {
return {
text: text,
toString: function () {return this.text},
capitalize: function () {
// return a new object instead of "this"
return {
text : _capitalize(this.text),
toString : this.toString
}
}
}
}
In Ruby I think you can call a method that hasn't been defined and yet capture the name of the method called and do processing of this method at runtime.
Can Javascript do the same kind of thing ?
method_missing does not fit well with JavaScript for the same reason it does not exist in Python: in both languages, methods are just attributes that happen to be functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is 100% methods.
What is needed in JavaScript is a hook to catch access to missing attributes, whether they are methods or not. Python has it: see the __getattr__ special method.
The __noSuchMethod__ proposal by Mozilla introduced yet another inconsistency in a language riddled with them.
The way forward for JavaScript is the Proxy mechanism (also in ECMAscript Harmony), which is closer to the Python protocol for customizing attribute access than to Ruby's method_missing.
The ruby feature that you are explaining is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm.
It's a brand new feature that is present only in some browsers like Firefox (in the spider monkey Javascript engine). In SpiderMonkey it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod
Please read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details about the upcoming implementation.
Not at the moment, no. There is a proposal for ECMAScript Harmony, called proxies, which implements a similar (actually, much more powerful) feature, but ECMAScript Harmony isn't out yet and probably won't be for a couple of years.
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, methodOrAttributeName) {
// target is the first argument passed into new Proxy, aka. target is myObj
// First give the target a chance to handle it
if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
return target[methodOrAttributeName];
}
// If the target did not have the method/attribute return whatever we want
// Explicitly handle certain cases
if (methodOrAttributeName === 'specialPants') {
return 'trousers';
}
// return our generic method_missing function
return function () {
// Use the special "arguments" object to access a variable number arguments
return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
+ methodOrAttributeName + '" called with: ['
+ Array.prototype.slice.call(arguments).join(',') + ']';
}
}
});
console.log(p.specialPants);
// outputs: trousers
console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs:
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]
About
You would use p in place of myObj.
You should be careful with get because it intercepts all attribute requests of p. So, p.specialPants() would result in an error because specialPants returns a string and not a function.
What's really going on with unknownMethod is equivalent to the following:
var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');
This works because functions are objects in javascript.
Bonus
If you know the number of arguments you expect, you can declare them as normal in the returned function.
eg:
...
get: function (target, name) {
return function(expectedArg1, expectedArg2) {
...
I've created a library for javascript that let you use method_missing in javascript: https://github.com/ramadis/unmiss
It uses ES6 Proxies to work. Here is an example using ES6 Class inheritance. However you can also use decorators to achieve the same results.
import { MethodMissingClass } from 'unmiss'
class Example extends MethodMissingClass {
methodMissing(name, ...args) {
console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
}
}
const instance = new Example;
instance.what('is', 'this');
> Method what was called with arguments: is this
No, there is no metaprogramming capability in javascript directly analogous to ruby's method_missing hook. The interpreter simply raises an Error which the calling code can catch but cannot be detected by the object being accessed. There are some answers here about defining functions at run time, but that's not the same thing. You can do lots of metaprogramming, changing specific instances of objects, defining functions, doing functional things like memoizing and decorators. But there's no dynamic metaprogramming of missing functions as there is in ruby or python.
I came to this question because I was looking for a way to fall through to another object if the method wasn't present on the first object. It's not quite as flexible as what your asking - for instance if a method is missing from both then it will fail.
I was thinking of doing this for a little library I've got that helps configure extjs objects in a way that also makes them more testable. I had seperate calls to actually get hold of the objects for interaction and thought this might be a nice way of sticking those calls together by effectively returning an augmented type
I can think of two ways of doing this:
Prototypes
You can do this using prototypes - as stuff falls through to the prototype if it isn't on the actual object. It seems like this wouldn't work if the set of functions you want drop through to use the this keyword - obviously your object wont know or care about stuff that the other one knows about.
If its all your own code and you aren't using this and constructors ... which is a good idea for lots of reasons then you can do it like this:
var makeHorse = function () {
var neigh = "neigh";
return {
doTheNoise: function () {
return neigh + " is all im saying"
},
setNeigh: function (newNoise) {
neigh = newNoise;
}
}
};
var createSomething = function (fallThrough) {
var constructor = function () {};
constructor.prototype = fallThrough;
var instance = new constructor();
instance.someMethod = function () {
console.log("aaaaa");
};
instance.callTheOther = function () {
var theNoise = instance.doTheNoise();
console.log(theNoise);
};
return instance;
};
var firstHorse = makeHorse();
var secondHorse = makeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
This doesn't work for my use case as the extjs guys have not only mistakenly used 'this' they've also built a whole crazy classical inheritance type system on the principal of using prototypes and 'this'.
This is actually the first time I've used prototypes/constructors and I was slightly baffled that you can't just set the prototype - you also have to use a constructor. There is a magic field in objects (at least in firefox) call __proto which is basically the real prototype. it seems the actual prototype field is only used at construction time... how confusing!
Copying methods
This method is probably more expensive but seems more elegant to me and will also work on code that is using this (eg so you can use it to wrap library objects). It will also work on stuff written using the functional/closure style aswell - I've just illustrated it with this/constructors to show it works with stuff like that.
Here's the mods:
//this is now a constructor
var MakeHorse = function () {
this.neigh = "neigh";
};
MakeHorse.prototype.doTheNoise = function () {
return this.neigh + " is all im saying"
};
MakeHorse.prototype.setNeigh = function (newNoise) {
this.neigh = newNoise;
};
var createSomething = function (fallThrough) {
var instance = {
someMethod : function () {
console.log("aaaaa");
},
callTheOther : function () {
//note this has had to change to directly call the fallThrough object
var theNoise = fallThrough.doTheNoise();
console.log(theNoise);
}
};
//copy stuff over but not if it already exists
for (var propertyName in fallThrough)
if (!instance.hasOwnProperty(propertyName))
instance[propertyName] = fallThrough[propertyName];
return instance;
};
var firstHorse = new MakeHorse();
var secondHorse = new MakeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
I was actually anticipating having to use bind in there somewhere but it appears not to be necessary.
Not to my knowledge, but you can simulate it by initializing the function to null at first and then replacing the implementation later.
var foo = null;
var bar = function() { alert(foo()); } // Appear to use foo before definition
// ...
foo = function() { return "ABC"; } /* Define the function */
bar(); /* Alert box pops up with "ABC" */
This trick is similar to a C# trick for implementing recursive lambdas, as described here.
The only downside is that if you do use foo before it's defined, you'll get an error for trying to call null as though it were a function, rather than a more descriptive error message. But you would expect to get some error message for using a function before it's defined.
Let's say I have an object that looks like this:
{
'apple': 'nice',
'banana': 'decent',
'cherry': 'yuck',
}
and I have these two methods:
function eatItems(cherry, apple) { }
function throwItem(banana) { }
My two questions:
Is it possible for me to invoke eatItem and send the arguments in the correct order? Maybe something like:
eatItems.call(this, {'cherry': cherry, 'apple': apple});
What if I don't know what arguments eatItems receives, can I dynamically look up the names of the arguments for a function so I can know the order that I need to throw them in?
There's a way, indeed, and it involves calling toString on a function:
var source = eatItems.toString();
// => "function eatItems(cherry, apple) { }"
The next step is to parse the string you've got to get the names of the arguments:
var args = source.substring(source.indexOf("(") + 1, source.indexOf(")")),
argNames = /\S/.test(args) ? args.split(/\s*,\s*/) : [];
A few caveats:
This solution has been kept quite simple. It doesn't handle comments in the function definition.
Not every browser can correctly convert a function to a string (the PS3 browser comes to my mind), but they're a really small minority anyway.
I haven't tested it, but there may be some performance issues on slower machines and/or older browsers with large functions.
And, overall, this solution is more like an exercise. I wouldn't recommend taking this pattern in Javascript. Don't forget that some functions handle a variable number of arguments, and you won't find them listed in their definition. Rethink your code, and find a better way.
If I understand correctly you want extract the argument names from the function, and inject data from an object based on those names. This can be accomplished by converting the function to a string, extracting the arguments, and applying the function with those arguments:
function inject(data, f) {
var args = f.toString()
.match(/function\s*?\((.+?)\)/)
.pop()
.split(',')
.map(function(a){return data[a.trim()]})
return function() {
return f.apply(this, args)
}
}
var data = {
apple: 'nice',
banana: 'decent',
cherry: 'yuck',
}
var eat = inject(data, function(cherry, apple) {
console.log(cherry, apple)
})
eat() //=> yuck, nice
The obvious problem with this approach is that it is highly dependent on the variable names, so when you minify your code, the variables will get mangled and the function will stop working. This is a known problem in AngularJS, which uses something similar for their dependency injection.
This is often an XY problem, or an anti-pattern at the very least.
With libraries such as ES5-Shim, we can use the new hotness now. Many methods on arrays (like forEach, map, every, etc) could be used now to write clean and beautiful code.
I'd like to have a list a practical uses I can have right now with those new methods when working with the current browsers' API (such as the DOM) or with just javascript.
I'm talking about this kind:
var nodes = document.getElementsByClassName('class')
[].forEach.call(nodes, callback)
function callback(node) {
console.log(node)
}
Another example from #Esailija:
[].filter.call( document.myform.elements, function(input){
return input.type == "text";
});
This is the kind of practical use I'm looking for. Some kind of patterns I'd be able to use in real projects.
The first thing you really will be able to use is the bind() method, I think.
var o = {
act: function() { ...}
}
// Instead of
element.addEventListener("type", function(){ o.act(); }, false)
// you can write
element.addEventListener("type", o.act.bind(o), false)
which is very useful in namespaced modules, where this is everything.
The array iterator methods are useful everywhery when it comes to data handling. No specific examples.
You can use iterator functions to manipulate lists.
So before you used for or while loops and now you use functions.
function isTextNode(node) {
return node.nodeType === Node.TEXT_NODE
}
function extractText(node) {
return node.data
}
function combineText(memo, text) {
return memo += text
}
var text = toArray(nodeList).filter(isTextNode).map(extractText).reduce(combineText)
To get used to "how or why this is useful" stop using for/while and think of your data as sets or lists and think about how you would filter / map / reduce these lists to extract data.
Also make an exercise to not use closures and have your iterator functions seperate and not bound over upvalues.
I have a function that takes a string object name and I need the function to create an new instance of a object that has the same name as the value of the string
For example,
function Foo(){}
function create(name){
return new name();
}
create('Foo'); //should be equivalent to new Foo();
While I know this would be possible via eval, it would be good to try and avoid using it. I am also interested if anyone has an alternative ideas to the problem (below)
I have a database and a set of (using classical OO methodology) classes, roughly one for each table that define common operations on that table. (Very similar to Zend_Db for those who use PHP). As everything is asynchronous doing tasks based on the result of the last one can lead to very indented code
var table1 = new Table1Db();
table1.doFoo({
success:function(){
var table2 = new Table2Db();
table2.doBar({
notFound:function(){
doStuff();
}
});
}
});
The obvious solution is to create helper methods that abstracts the asynchronous nature of the code.
Db.using(db) //the database object
.require('Table1', 'doFoo', 'success') //table name, function, excpected callback
.require('Table2', 'doBar', 'notFound')
.then(doStuff);
Which simplifies things. However the problem is that I need to be able to create the table classes, the names of which can be inferred from the first augment passed to require which leads me to the problem above...
Why not simply pass the constructor function into the require method? That way you sidestep the whole issue of converting from name to function. Your example would then look like:
Db.using(db) //the database object
.require(Table1Db, 'doFoo', 'success') //table constructor, function name, expected callback
.require(Table2Db, 'doBar', 'notFound')
.then(doStuff);
However, if you really want to use a string...
Why are you deadset on avoiding using eval? It is a tool in the language and every tool has its purpose (just as every tool can be misused). If you're concerned about allowing arbitrary execution, a simple regular expression test should render your usage safe.
If you're dead-set on avoiding eval and if all of your constructor functions are created in the default global scope (i.e. the window object), this would work:
function create(name) {
return new window[name]();
}
If you want to get fancy and support namespace objects (i.e. create('MyCompany.MyLibrary.MyObject'), you could do something like this:
function create(name) {
var current,
parts,
constructorName;
parts = name.split('.');
constructorName = parts[parts.length - 1];
current = window;
for (var i = 0; i < parts.length - 1; i++) {
current = current[parts[i]];
}
return new current[constructorName]();
}
You were at the gate of completeness. While Annabelle's solution let's you to do what's you've just wanted in the way you wanted (passing strings), let me offer you an alternative. (passing function references)
function Foo(){}
function create(name){
return new name();
}
create(Foo); // IS equivalent to new Foo();
And voila, it works :) I told you. You were at the doorsteps of the solution.
What happened is that you've try to do this
new 'Foo'()
Which doesn't makes much sense, does it? But now you pass the function by reference so the line return new name(); will be transformed into return new Foo(); just how you would expect.
And now the doors are opened to abstract the asynchronousness of your application. Have fun!
Appendix: Functions are first-class objects, which means that they can be stored by reference, passed as an argument by reference or returned by another function as values.