I have 2 functions and one constructor defined like this :
let mx = function(arr) {
return new mx.fn.init(arr)
}
mx.fn = mx.prototype = {
constructor: mx,
}
init = mx.fn.init = function(arr) {
//do things and return an object containing data about arr
}
So this code works well and calling mx(array) returns the wanted object.
Now, how can I define functions to manipulate this object? I would like to define functions like, for example, mx(array).addRow(row) to change data in the object returned by mx(array) but can't manage to do it.
I tried to define it in mx.fn like this :
addRow: function(arr) { //do smth } but it doesn't work.
I also tried to do mx.prototype.addRow = function(row) { //do smth }.
Do you know if this is possible? It looks like jQuery's $('#id').css('color': 'red') a lot but I'm not sure if this works the same way.
I'm new to a lot of these concepts so I'm a bit lost in all those prototypes...
Thanks in advance for your help!
You need to set the prototype of the init function.
let mx = function(arr) {
return new mx.fn.init(arr)
}
let init = function(arr) {
//do things and return an object containing data about arr
}
mx.fn = init.prototype = {
addRow(row){
// do something
},
init: init
}
Related
I'm trying to write a functional library in JavaScript. I'm also using lodash.
What I've got so far, abstractly:
x = _.curry(function(property, data) {
return data.get(property);
});
With this, you can do x(1)(2) and x(1, 2), and everything works as expected.
Say I want to modify the function so that it data can be an array:
x = _.curry(function(property, data) {
if (_.isArray(data)) {
return _.map(data, x(property));
} else {
return item.get(property);
}
});
Now that works great. But I've got 30+ functions. There's got to be a better way than manual if (_.isArray(data)... else... writing for each function. A decorator maybe?
decorate = function(func) {
// return a curried func and handle the aforementioned _.isArray
}
x = decorate(function(property, data) {
if (_.isArray(data)) {
return _.map(data, x(property));
} else {
return item.get(property);
}
});
I'm completely lost on how to write the decorate function: A function that can take arity 2 and arity 3 functions to decorate.
First you wrap the original function with one that maps array arguments, then you curry that wrapped version.
var decorate = function(func) {
var mapIfArray = function(property, data) {
if (_.isArray(data)) {
return _.map(data, _.curry(func)(property));
} else {
return func(property, data);
}
}
return _.curry(mapIfArray);
}
You would use it like this:
var undecorated = function(property, data) {
return data.get(property);
}
var decorated = decorate(undecorated);
That's assuming all your undecorated functions are arity 2, with the possible array at the end. If that's not the case, you'll either have to create different decorators for different arities, or do some sort of voodoo with the arguments object.
I'm not really sure what you're trying to accomplish but could something like this work? This is a bit hacky but idea is to pass the function from the outside.
x = _.curry(function(func, data) {
return _.map(_.flatten([data]), func);
});
What I am thinking of writing is something like this.
Object.prototype.toString = function(){
var ret = '{';
for(var i in this){
if(this[i].toString)
ret = ret + ( '"'+i+'":' + this[i].toString())
}
ret=ret+'}'; return ret;
}
I will do this for Number and other known dataTypes.
I have seen many utils.stringify fucntions available , along with JSON.stringify, what all these libs are doing is that, they are checking type of object and based on that they concatenating strings to create Json. which is ok, I cant use those fucntions because I want to use something like this: -
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toString = function(){
return this.data.toString()
}
}
utils.parse(({
x : new subMap()
}).toString())
which should return something like this
"{"x":{"a":"A","b":"B"}}"
Basically I want to have way where I can decide how to represent StringFormat(JSON) for any ObjectType, whenever I add a new DataType.
But looking at all the available libs I see no one is doing this way(defining toString function), which i m thinking is better way. Is there any drawback or something JavaScript is using it internally to do something which will break something or any other reason they are not using it?
Edit
I found the answer. at link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toJSON = function(){
return this.data;
}
}
should work as I expect.
You can use the second argument to JSON.stringify(value, replacer, space) to do this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Try using toJSON
function subMap(){
this.data = { a : 'A', b : 'B'}
this.toJSON = function(){
return this.data;
}
}
this may solve your problem
Recently I was playing around with writing a small library for music theory in JS. One of the features I wanted to add was a jQuery style selector for creating/finding notes. For example:
Notes("a#") === Note {_note: 0, accidental: 1}
However, the structure of the library looked something akin to:
var Notes = function(sel) {
// initialisation stuff
var Note = function() {
// stuff for note objects
};
var scales = {
...
};
var selector(sel) {
// evaluate sel
return new Note(...);
};
if(sel !== undefined) {
return selector(sel);
}
return {
Note: Note,
scales: scales
};
};
module.exports = new Notes();
This way, I could use the library like this:
var Notes = require("Notes");
Notes.scales.major.c === [0,2,4,...];
But not like this:
var thisNote = Notes("A#");
As Notes was obviously an object that had been returned from the original Notes function. To use the selector function I'd have to expose it and then call it like this:
var thisNote = Notes.selector("A#");
But I want to mimic the jQuery/sizzle style (I had a bit of a search of jQuery's source, but couldn't find anything that helped).
How can I/should I have approached the design to allow for this kind of functionality? Would using prototypes instead of Closures been a more sensical approach? Or should I have aliased the library's name to another method to achieve the desired effect?
jQuery is like this:
function wrap() {
// do wrapping of DOM nodes
return {
value: function () { /*..*/ },
add_class: function () { /*..*/ }
};
}
wrap.extend = function () { /*..*/ }
wrap.ajax = function () { /*..*/ }
wrap("#abc"); // has `.value` and `.add_class)
wrap.ajax();
Instead of just saying:
var thing = timeConsumingMethod();
I have my variable hidden in a method like so:
function _thing() {
var thing = timeConsumingMethod() );
return thing;
}
It gets called a number of times. I'm concerned that I'm made things very inefficient. I assume it calls timeConsumingMethod every time (which is unneeded, it's always the same) I call "_thing()" to get my variable.
How do I manage these types of variables in simple efficient way? Is something like this a solution?:
function _thing() {
return _thing.thing
}
_thing.thing = timeConsumingMethod();
Basically, i want the protection of a function and to (ideally0 access my variable using _thing() or something similar, but I only want timeConsumingMethod to run once.
edit: tried this, doesn't work either:
function _thingy() {
var thing = timeConsumingMethod();
}
_thingy.test = function() {
return( _thingy.thing)
}
Why not just:
function SomethingTimeConsuming() { ... }
function LazyThing(sourceFunction) {
this.sourceFunction = sourceFunction;
this.value = null;
this.Value = function() {
if ( this.value == null) this.value = sourceFunction();
return this.value;
}
}
JSFiddle: http://jsfiddle.net/YSAjJ/
Output:
[14:20:20.079] Calling time-consuming function *(1 time)
I'm working on some script for a set of functions that all operate from one call and take a large number of parameters to return one value. The main function requires the use of 11 other functions which need to work with the same parameters. I have it structured somewhat like this:
function mainfunction(param1, param2, ..., param16)
{
//do a bunch of stuff with the parameters
return output;
}
function secondaryfunction1()
{
//gets called by mainfunction
//does a bunch of stuff with the parameters from mainfunction
}
Is there anything I can do to make the parameters passed to mainfunction available to all the secondary functions without passing them or making them global variables? If not, that's fine, I'll pass them as parameters - I'm curious as to whether or not I can do it more elegantly.
You can place the definition of secondaryfunction1 inside mainfunction:
function mainfunction(param1, param2, ..., param16){
function secondaryfunction1() {
// use param1, param2, ..., param16
}
secondaryfunction1();
}
Update:
As #dystroy pointed out, this is viable if you don't need to call secondaryfunction1 somewhere else. Where the list of parameters would be coming from in this case - I don't know.
You could use arguments to pass to secondaryFunction1 all the arguments of mainfunction. But that would be silly.
What you should probably do, and what is usually done, is embed all the parameters in an "options" object :
function mainfunction(options){
secondaryfunction1(options);
}
function secondaryfunction1(options) {
// use options.param1, etc.
}
// let's call it
mainfunction({param1: 0, param2: "yes?"});
This leds to other advantages, like
naming the parameters you pass, it's not a good thing for maintenance to have to count the parameters to know which one to change. No sane library would let you pass 16 parameters as direct unnamed arguments to a function
enabling you to pass only the needed parameters (the other ones being default)
#Igor 's answer (or some variation) is the way to go. If you have to use the functions elsewhere, though (as #dystroy pointed out), then there is another possibility. Combine your parameters together into an object, and pass that object to the secondary functions.
function combineEm() {
// Get all parameters into an array.
var args = [].slice.call(arguments, 0),
output = {},
i;
// Now put them in an object
for (i = 0; i < args.length; i++) {
output["param" + i] = args[i];
}
return output;
}
From your main function, you can do:
function mainfunction(param1, param2, ..., param16) {
var params = combineEm(param1, param2, ..., param16);
var output = secondaryfunction(params);
// etc.
return output;
}
Edit: I just wanted to clarify that all of the proposed suggestions so far do work. They just each have their own trade-offs/benefits.
I tried just suggesting some changes to other answers, but ultimately I felt like I needed to just post my solution to this.
var externalFn = function(options) {
var str = options.str || 'hello world';
alert(str);
};
var main = function(options) {
var privateMethod = function() {
var str = options.str || "foobar";
alert("str: " + str);
};
// Bind a private version of an external function
var privateMethodFromExternal = externalFn.bind(this, options);
privateMethod();
privateMethodFromExternal();
};
main({ str: "abc123"});
// alerts 'str: abc123'
// alerts 'abc123'
main({});
// alerts 'str: foobar'
// alerts 'hello world'
It seems like the main point of the question is that the functions used by the 'main function' shouldn't have to keep having the options/context passed to them.
This example shows how you can use privateMethods inside the function
It also shows how you can take external functions (that you presumably use outside of main) and bind a private method version of them for use inside main.
I prefer using some sort of 'options' object, but that aspect isn't really that important to the question of scoping that the OP was really asking about. You could use 'regular' parameters as well.
This example can be found on codepen.
Here's an incredibly naughty solution, if you're interested in that sort of thing.
var f1 = function() {
var a = 1;
var _f2 = f2.toString().replace(/^function[^{}]+{/, '');
_f2 = _f2.substr(0, _f2.length - 2);
eval(_f2);
}
var f2 = function(a) {
var a = a || 0;
console.log(a);
}
f2(); // logs 0
f1(); // logs 1
It executes the contents of some external function entirely in the current scope.
However, this sort of trickery is almost definitely an indicator that your project is mis-organized. Calling external functions should usually be no more difficult than passing an object around, as dystroy's answer suggests, defining the function in-scope, as Igor's answer suggests, or by attaching some external function to this and writing your functions primarily against the properties of this. Like so:
var FunLib = {
a : 0,
do : function() {
console.log(this.a);
}
}
var Class = function() {
this.a = 1;
this.do = FunLib.do;
this.somethingThatDependsOnDo = function() {
this.a++;
this.do();
}
}
var o = new Class();
FunLib.do() // 0
o.do() // 1
o.somethingThatDependsOnDo(); // 2
o.do() // 2 now
Similarly, and possibly better-solved with a class hierarchy.
function BasicShoe {
this.steps_taken = 0;
this.max_steps = 100000;
this.doStep = function() {
this.steps_taken++;
if (this.steps_taken > this.max_steps) {
throw new Exception("Broken Shoe!");
}
}
}
function Boot {
this.max_steps = 150000;
this.kick_step_equivalent = 10;
this.doKick = function() {
for (var i = 0; i < this.kick_step_equivalent; i++) {
this.doStep();
}
}
}
Boot.prototype = new BasicShoe();
function SteelTippedBoot {
this.max_steps = 175000;
this.kick_step_equivalent = 0;
}
SteelTippedBoot.prototype = new Boot();