How do I make this simple javascript function? - javascript

I have three variables
var r1 = 12;
var r2 = '';
var r3;
I need to make a function convert() with three parameters as so:
function convert(arg1, arg2, arg3) {
// function body here
}
such that after I run this code
convert(r1, r2, r3)
console.log(r1, r2, r3)
I should get the output:
r2, "empty string", "undefined value"
That is it should changed the values of r1, r2 and r3 to the above values.
Code I tried:
function convert(arg1, arg2, arg3) {
if (arg2 === '') {
arg2 = "empty string";
}
if (arg3 === undefined) {
arg3 = "undefined value";
}
}
and then call convert(r1, r2, r3) it fails (obviously!) because of arguments are passed as values. But I need to know is there any way to make this function? Also, I have seen this question, so I know about how they are passed, but still, is there any way I can make this work?

You could do something like this, but most likely something is flawed with your logic.
function convert(arr) {
for (var i = 0, l = arr.length; i < l; i++) {
// do your stuff here on arr[i]
}
return arr;
}
var a = convert([r1, r2, r3]);
//a now holds the right values, do whatever you want with them
//you can even load them back to the variables if that's what you really want
//r1 = a[0]; etc.
I don't know what is the reason to do this, where you want to use these new values, but it would be more clever to write the convert function for only one value, and call it when it's necessary.
function convert(val) {
if (val === '') {
return 'empty string';
}
if (typeof val === 'undefined') {
return 'undefined value';
}
return val;
}
console.log(convert(r1));

You can't do this in JavaScript. It doesn't have pass-by-reference semantics.
You can use an intermediate object fo this, but seems that's not what you are looking for:
var data = {r1: 12, r2: '', r3: undefined};
function convert(data, field1, field2, field3) {
// …
}

In the unlikely event that you only want to convert global variables, you can just pass in the names of those variables:
function convert(arg1, arg2, arg3) {
if (window[arg2] === '') {
window[arg2] = "empty string";
}
if (window[arg3] === undefined) {
window[arg3] = "undefined value";
}
}
var r1 = 12;
var r2 = '';
var r3;
convert('r1', 'r2', 'r3');
console.log(r1, r2, r3);

working code:
fire the execute function on the event you need
function execute(){
var r1 = 12;
var r2 = '';
var r3;
convert(r1,r2,r3);
}
function convert(arg1, arg2, arg3) {
if (arg2 === '') {
arg2 = "empty string";
}
if (arg3 === undefined) {
arg3 = "undefined value";
}
console.log(arg1,arg2,arg3);
// console.log(arg2);
// console.log(arg3);
}

Related

Call a result of a function inside a function

I want to bring out the results of a function that is within another function. When I try to print or return results it only brings out the result of the function "Sum".
let readlineSync = require("readline-sync");
let a = readlineSync.question(
"Choose an operation: Sum or Substraction: "
);
let param1 = parseInt(readlineSync.question("Value 1: "));
let param2 = parseInt(readlineSync.question("Value 2: "));
chosenFunction();
function Sum() {
return param1 + param2;
}
function Substraction() {
return param1 - param2;
}
function chosenFunction() {
let result;
if (a = 'Sum') {
result = console.log (Sum());
} else if (a = 'Substraction') {
result = console.log ( Substraction());
}
return result
}
It's an invalid usage,when you assign value,you need to remove console.log
Also need to change = to == when compare values
So change
result = console.log (Sum());
result = console.log ( Substraction());
to
result = Sum();
result = Substraction();
Full code
function chosenFunction() {
let result;
if (a == 'Sum') {
result = Sum();
} else if (a == 'Substraction') {
result = Substraction();
}
return result
}
You need to use == or ===. You are actually changing your values, not comparing, when using = as in else if (a = 'Substraction').
if (a === 'Sum')
else if (a === 'Substraction')

memoize any given recursive function in JavaScript

I am interested in the scenario where we have some function f which is recursive and which we are not provided the source code to.
I would like a function memoizer: Function -> Function which takes in say f and returns a function g such that g = f (in the sense they return the same value given the same arguments) which when called first checks if the called arguments are in its 'cache' (memory of results it has calculated before) and if so returns the result from this, otherwise it should compute f, should f call itself with some arguments, this is tantamount to calling g with those arguments and I would like that f first check if the cache of g contains those arguments and if so return the result from this, otherwise ...
This is easy (in Javascript) to do given the source code of f, I simply define memoize in the obvious way and do something like
let f = memoize((...args) => {/* source code of f */});
But this doesn't appeal to me at all (mainly because I might want a memoized and non memoized version of the same function and then I'd have to write the same function twice) and won't work if I don't know how to implement f.
In case it's not clear what I'm asking,
I would like a function memoize which takes a function such as
fact = n => n === 0 ? 1 : n * fact(n - 1);
And returns some new function g such that fact(n) = g(n) for all n and which for example when g(10) is computed stores the values of fact(0), ..., fact(10) which are computed while computing g(10) and then if I ask for say g(7) it finds the result in the cache and returns it to me.
I've thought that conceptually it's possible to detect when f is called since I have it's address and maybe I could replace all calls to f with a new function where I compute f and store the result and then pass the value on to where it would normally go. But I don't know how to do this (and it sounds unpleasant).
maybe I could replace all calls to f with a new function where I compute f and store the result and then pass the value on to where it would normally go.
This is actually very easy to do, as Bergi referred to in a comment.
// https://stackoverflow.com/questions/24488862/implementing-automatic-memoization-returns-a-closured-function-in-javascript/
function memoize(func) {
var memo = {};
var slice = Array.prototype.slice;
return function() {
var args = slice.call(arguments);
if (args in memo)
return memo[args];
else
return (memo[args] = func.apply(this, args));
}
}
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
fib = memoize(fib);
console.log(fib(100));
I might want a memoized and non memoized version of the same function and then I'd have to write the same function twice
Yes, you need to. The recursive call to fact(n - 1) inside the function can only refer to one fact function - either a memoized or an unmemoized one.
So what you need to do to avoid code duplication is define fact with the Y combinator:
const makeFact = rec => n => n === 0 ? 1 : n * rec(n - 1);
// ^^^ ^^^
const factA = Y(makeFact);
const factB = memoizingY(makeFact);
function Y(make) {
const f = make((...args) => f(...args)); // const f = make(f) is easier to understand
return f; // but doesn't work with eager evaluation
}
I'll leave the definition of memoizingY as an exercise to the reader :-)
Possibly simpler approach:
const makeFact = annotate => {
const f = annotate(n => n === 0 ? 1 : n * f(n - 1));
return f;
}
const factA = makeFact(identity);
const factB = makeFact(memoize);
In my limited experience, we do have access to JavaScript source code. We could thus attempt to generate new source code for the memoized function.
// Redefine Function.prototype.bind
// to provide access to bound objects.
// https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
var _bind = Function.prototype.apply.bind(Function.prototype.bind);
Object.defineProperty(Function.prototype, 'bind', {
value: function(obj) {
var boundFunction = _bind(this, arguments);
boundFunction.boundObject = obj;
return boundFunction;
}
});
// Assumes the parameters for the function,
// f, can be consistently mapped.
function memo(f){
if (!(f instanceof Function))
throw TypeError('Argument is not an instance of Function.');
// Generate random variable names
// to avoid conflicts with unknown
// source code
function randomKey(numBytes=8){
let ranges = [[48, 10], [65, 26], [97, 26]];
let key = '_';
for (let i=0; i<numBytes; i++){
let idx = Math.floor(Math.random() * ranges.length);
key += String.fromCharCode(ranges[idx][0] + Math.random() * ranges[idx][1]);
}
return key;
}
let fName = f.name;
let boundObject;
let fCode;
const nativeCodeStr = '(){[nativecode]}';
// Possible Proxy
try {
fCode = f.toString();
} catch(error){
if (error.constructor == TypeError){
if (Function(`return ${ fName }.toString()`)() != nativeCodeStr){
throw TypeError(`Possible Proxy detected: function has a name but no accessible source code. Consider memoizing the target function, ${ fName }.`);
} else {
throw TypeError(`Function has a name but no accessible source code. Applying toString() to its name, ${ fName }, returns '[native code]'.`);
}
} else {
throw Error('Unexpected error calling toString on the argument.');
}
}
if (!fName){
throw Error('Function name is falsy.');
// Bound functions
// Assumes we've monkey-patched
// Function.prototype.bind previously
} else if (fCode.replace(/^[^(]+|\s+/g, '') == nativeCodeStr){
if (/^bound /.test(fName)){
fName = fName.substr(6);
boundObject = f.boundObject;
// Bound functions return '[native code]' for
// their toString method call so get the code
// from the original function.
fCode = Function(`return ${ fName }.toString()`)();
} else {
throw Error("Cannot access source code, '[native code]' provided.");
}
}
const fNameRegex = new RegExp('(\\W)' + fName + '(\\W)', 'g');
const cacheName = randomKey();
const recursionName = randomKey();
const keyName = randomKey();
fCode = fCode.replace(/[^\(]+/,'')
.replace(fNameRegex, '$1' + recursionName + '$2')
.replace(/return/g, `return ${ cacheName }[${ keyName }] =`)
.replace(/{/, `{\n const ${ keyName } = Array.from(arguments);\n\n if (${ cacheName }[${ keyName }])\n return ${ cacheName }[${ keyName }];\n`);
const code = `function(){\nconst ${ cacheName } = {};\n\nfunction ${ recursionName + fCode }\n\nreturn ${ recursionName }.apply(${ recursionName }, arguments);}`;
let g = Function('"use strict";return ' + code)();
if (boundObject){
let h = (g).bind(boundObject);
h.toString = () => code;
return h;
} else {
return g;
}
} // End memo function
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
const h = fib.bind({a: 37});
const g = memo(h);
console.log(`g(100): ${ g(100) }`);
console.log(`g.boundObject:`, g.boundObject);
console.log(`g.toString():`, g.toString());
try{
memo(function(){});
} catch(e){
console.log('Caught error memoizing anonymous function.', e)
}
const p = new Proxy(fib, {
apply: function(target, that, args){
console.log('Proxied fib called.');
return target.apply(target, args);
}
});
console.log('Calling proxied fib.');
console.log(`p(2):`, p(2));
let memoP;
try {
memoP = memo(p);
} catch (e){
console.log('Caught error memoizing proxied function.', e)
}

Javascript object members

var math = {
Factorial:function(n) {
if (n == 0) {
return 1;
}
return n * Factorial(n - 1);
},
CalculateFactorial:function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = Factorial(myValue);
document.getElementById('title').innerHTML = result;
}
}
Hello guys. New to JavaScript and testing different things, coming from C# language things are pretty the same yet different.
I am trying to do something and no success.
Having the script above attached to a simple html button , trying to call the CalculateFactorial , math.CalculateFactorial(); , but what is wierd is that CalculateFactorial() doesn't actually see the Factorial() method. But in the math object I can see both methods. Wierd.
"JavaScript runtime error: 'Factorial' is undefined"
A good practice in JavaScript is to name all of your functions even if you assign them to a variable or use them like object's property. In your case just give a name to your Factorial function like this:
Factorial:function factorial(n)
{
if (n == 0)
{
return 1;
}
return n * factorial(n - 1);
},
For the problem of not seeing Factorial in your CalculateFactorial function just use this.Factorial when you invoke it.
This should fix the issue... if you want Factorial to be an internal only function (just a utility for the exposed CalculateFactorial) then you can do so this way:
var math = new function() {
var $this = this;
var Factorial = function(n) {
if (n == 0) {
return 1;
}
return n * Factorial(n - 1);
}
$this.CalculateFactorial = function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = Factorial(myValue);
document.getElementById('title').innerHTML = result;
}
}
The deeper design issue here is this is not particularly reusable javascript. You should consider pulling CalculateFactorial() out of the math object and into it's own handler... probably a click handler would be my guess like this:
var math = new function() {
var $this = this;
$this.Factorial = function(n) {
if (n == 0) {
return 1;
}
return n * $this.Factorial(n - 1);
}
}
$("#calcButton").click(function() {
var myValue = document.getElementById('myTextBox').value;
if (myValue.length == 0) {
alert("Please input the correct value!");
return;
}
var result = math.Factorial(myValue);
document.getElementById('title').innerHTML = result;
})
That happens beceause the Factorial method is part of the math object, and it doesn't reside in the global scope. When you try to call it directly, the parser will try to find that method into the global scope, and then, it will thrown an ReferenceError.
Since you're using the method inside the object itself, you can use the this keyword, because it will look into the object's context and find the method Factorial.
Another way of calling the Factorial method is by using the object, e.g: math.Factorial.
Take a look at the example below:
var math = {
Factorial: function(n) {
return n === 0 ? 1 : n * this.Factorial(n - 1);
},
CalculateFactorial: function(txt) {
document.getElementById('title').innerHTML = this.Factorial(txt.value);
}
};
document.getElementById('myTextBox').addEventListener('input', function() { math.CalculateFactorial(this); });
<input type="text" id="myTextBox" placeholder="Fatorial">
<div id="title"></div>

Insert a line into a function in JavaScript

In JavaScript, is it possible to insert a line into a function that already exists? I want to create a function that inserts a line at a specific position in a function:
function insertLine(theFunction, lineToInsert, positionToInsert){
//insert a line into the function after the specified line number
}
For example, would it be possible to programmatically insert the line checkParameterTypes(min, "string", max, "string"); before the first line of this function?
function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want something to happen at the beginning of a function, you can use the following. You do have access to this and the arguments from your injected function. So it will still work for functions that require a specific context.
function inject(before, fn) {
return function(){
before.apply(this, arguments);
return fn.apply (this, arguments);
}
}
For example
function add(a, b) {
return a + b;
}
function concat(a, b) {
return a + b;
}
/**
* You can repeat index and type to check multiple arguments
*/
function createArgumentChecker(index, type /**index, type, ... */) {
var originalArgs = arguments;
return function() {
for (var i=0; i < originalArgs.length; i+=2) {
var index = originalArgs[i],
requestedType = originalArgs[i+1],
actualType = typeof arguments[index];
if (typeAtIndex != actualType) {
console.log("Invalid argument passed at index " + index +
". Expected type " + requestedType + "but it's " + actualType );
}
}
}
}
function logArguments() {
console.log(this, arguments);
}
// Inject an argument checker
add = inject(add, createArgumentChecker(0,"number", 1, "number"));
concat = inject (concat, createArgumentChecker(0, "string", 1, "string"));
// You can even do it multiple times, inject an argument logger;
add = inject(add, logArguments);
concat = inject(concat, logArguments);
JSfiddle
This can be handy when debugging websites that you can't modify the source code, I wouldn't use it do parameter checking unless you can strip it our for the production version.
Yes you can but using eval is always evil ;)
function insertInbetween (arr, value, index) {
var inserted, i, newarr = [];
for (i = 0; i < arr.length; i++) {
if(i == index && !inserted) {
newarr[i] = value;
inserted = true;
}
newarr.push(arr[i]);
}
return newarr;
}
function test (a, b) {
console.log(a,b);
}
var fstrarr = test.toString().split('\n');
eval(insertInbetween(fstrarr, "console.log('injected!');", 1).join('\n'));
Edit:
As mentioned in the comments to your question you'll loose scope by doing so.

Can't iterate array returned from Sizzle

From my understanding Sizzle returns an array of objects (DOMElements), I am trying to walk that array of objects in a for loop but I am getting errors. When I try to get a property with the
obj[index-number]["property"]
it works fine, but when I try to access it after passing it to another function
obj[index-number][arguments[index-number]]
I am getting a return of undefined. I have tried many different ways, including eval to parse the dot notation to no avail. I am stumped. Any pointers or ideas would be awesome. Also, I have verified all input to the function is correct (through alerting them out), also, hard coding the values to get what I want in the function works as well. Here is my code: (sorry it's lengthy).....
var ecmafw = function() {
// Creates the new instance of the object.
// Sets up the objects global properties:
this.error = false;
// Checks to see if arguments were supplied, if none are then it returns false.
if (arguments.lenght == 0) {
this.error = "No arguments were supplied.";
return false;
}
// Gives a reference to the result set.
this.results = Sizzle(arguments[0]);
this.attr = function() {
/* Purpose: To add/remove/update an attribute from the results set.
*
* Can be used in two ways:
* 1: .attr("attribute1='value' attribute2='value' attribute3='value'") // adds/removes them all. [negate value to be removed with "-" (used for class)]
* 2: .attr("attribute", "value") // adds the one. [negate value to be removed with "-" (used for class)]
* 3: .attr("attribute") // removes the one.
* 4: .attr("attribute1 attribute2 attribute3") // removes them all.
*/
var len = this.results.length;
switch (arguments.length) {
case 1:
for (var a=0; a < len; a++) {
var re = new RegExp("=", "g");
if (re.test(arguments[0])) {
// Provided a list of attributes to update/create.
valuePairs = arguments[0].split("' ");
for (var i=0; i < valuePairs.length; i++) {
var attributeValue = valuePairs[i].split("=");
var newRE = new RegExp(/^-/);
var value = attributeValue[1].replace(/'/g, "");
if (newRE.test(value)) {
this.removeAttr(attributeValue[0], a, value);
} else {
this.setAttr(attributeValue[0], value, a);
}
}
} else {
var attributeSplit = arguments[0].split(" ");
if (attributeSplit.length == 1) {
// Provided a single attributes to remove.
this.removeAttr(arguments[0], a);
} else {
// Provided multiple attributes to remove.
for (var i=0; i < attributeSplit.length; i++) {
this.removeAttr(attributeSplit[i], a);
}
}
}
}
break;
case 2:
// Provided a single name/value pair to update.
for (var a=0; a < len; a++) {
this.setAttr(arguments[0], arguments[1], a)
}
break;
default:
// Either 0 or more than 2 arguments were supplied.
this.error = "There were no arguments supplied with the attr() function, or there were too many supplied.";
return false
break;
}
};
this.setAttr = function() {
// Counters for IE className
if (document.all && !window.opera) {
arguments[0] = arguments[0].replace(/class/gi, "className");
}
if (arguments[0] == "class" || arguments[0] == "className") {
if (this.results[arguments[2]][arguments[0]] != undefined) {
arguments[1] += " " + this.results[arguments[2]][arguments[0]]; // Failing
}
}
if (this.results[arguments[2]].setAttribute) {
this.results[arguments[2]].setAttribute(arguments[0], arguments[1]);
} else {
this.results[arguments[2]][arguments[0]] = arguments[1];
}
};
this.removeAttr = function() {
arguments[0] = arguments[0].replace(/class/gi, "className");
var item = this.results[arguments[1]];
if (arguments[0] == "className") {
arguments[2] = arguments[2].replace("-", "");
var replaceRE = new RegExp(arguments[2], "gi");
// For some reason it would find it like this, This is fine but it is not working
// in Opera. Opera is failing to convert item[eachItem] to an object. (so it says in its error log)
for (var eachItem in item) {
if (arguments[0] == eachItem) {
item[eachItem] = item[eachItem].replace(replaceRE, " ");
item[eachItem] = item[eachItem].replace(/ /gi, " ");
item[eachItem] = item[eachItem].replace(/^ /gi, "");
item[eachItem] = item[eachItem].replace(/ $/gi, "");
}
}
} else {
if (this.results[arguments[1]].removeAttribute) {
this.results[arguments[1]].removeAttribute(arguments[0]);
} else {
this.results[arguments[1]][arguments[0]] = "";
}
}
};
// Returns a reference to itself.
return this;
}
Not sure if this might be the problem, but in the removeAttr function you are accessing the 3rd argument passed in on this line:
arguments[2] = arguments[2].replace("-", "");
However, in 2 of the 3 calls to this function you only pass in 2 arguments. If the above line runs in either of those cases arguments[2] would be undefined and calling replace("-", "") on it would throw an error.
Also, you have a typo in your initial arguments check near the top: arguments.lenght.

Categories