Im new to JS and trying to learn. The spec requires the following:
Write a function that takes another function* as an argument and creates a version of the function that can only be called one time. Repeated calls to the modified function will have no effect, returning the value from the original call. How could you do this without using a closure? Is it even possible? How could you do this with a closure? *Note: This original input function should not have any parameters.
This is what I have:
var divide = function () {
var x = 2;
var y = 6;
return y/x;
}
var mainFunc = function (func) {
return func(){
return y/x + 1;
}
}
var output = mainFunc(divide);
console.log(divide());
console.log(output());
console.log(output());
I'm getting an "Unexpected token{" error at "return func(){" I don't quite understand what i'm doing wrong? Per the spec, I am passing divide() to mainFunc() and setting it to a reference variable output. I then call the divide() and output() multiple times to test if the closure works and that modified function only happens once. What am I missing or not understanding?
Thanks for the help.
Here you go:
function runonce(func) {
return (function(func) {
var ran = false;
var retval;
return function() {
if (!ran) {
ran = true;
retval = func();
}
return retval;
}
})(func);
}
function realfunction() {
console.log('really running');
return 5;
}
var realfunctionrunner = runonce(realfunction);
realfunctionrunner();
realfunctionrunner();
realfunctionrunner();
Study the code, the whole trick is a "self contained library" which result is returned from the runonce function
Related
I'm trying to understand exactly how this Once function by David Walsh works:
`
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
`
I understand it takes a function as a argument, and returns a function that calls the passed function only once.
But I'm trying to understand what each part is doing. Can anyone help explain? especially this part:
result = fn.apply(context || this, arguments);
Why the OR sign? what is "this" and how is it getting the arguments from fn? What purpose does 'context' serve?
I wrote a similar once() function for school that returns the result of the passed function, and stores the result to return it again if the function attempts to get called again. It took a lot of trial and error, and I'm just trying to get a firm grasp on all the component parts of how this works.
`
function add(x, y) {
return x + y;
}
function once(fn) {
let timesRan = 0;
let result;
function doOnce() {
if (timesRan === 0) {
timesRan = 1;
result = fn.apply(this, arguments); //I don't understand how this gets the arguments from AddOnce
console.log(`did it once: ${result}`)
return result;
} else {
return result;
}
}
return doOnce;
}
var addOnce = once(add);
console.log(addOnce(1, 2)); // test first call, expected value: 3
console.log(addOnce(2, 5)); // test second call, expected value: 3
console.log(addOnce(8, 22)); // test third call, expected value: 3
`
The concept behind this in JavaScript is confusing, because when I write a function such as:
function getPersonName() {
return this.name
}
I expect that this be defined as a some object with a name attribute. Depending on the scope, I may have this be defined and no problems! But in order for a function such as the above to properly reference this, we need to tell it what it should reference when we use that keyword.
For example, it allows us to do the following:
var canOnlyFireOnce = once(function() {
console.log(this.name)
}, {name: "John"});
canOnlyFireOnce() // prints John
canOnlyFireOnce() // nada
It may be helpful to understand the bind function's use cases in JavaScript to understand why having this (no pun intended) is useful.
The meaning of the this context in function.apply is already explained in rb612's answer.
For the question about arguments, you need to know that
the arguments object is a local variable available within all non-arrow functions. You can refer to a function's arguments inside that function by using its arguments object.
i have 2 different javascript environments and want to create a library usable on both. to do that i want to use higher order functions to generate my functions, like so
try {
Maptool.chat.broadcast("")
var myFunc1 = genFunction1("env1");
}
catch(e){
if(e instanceof ReferenceError){
var myFunc1 = genFunction1("env2")
}
}
genFunction1 would return a function that i could call built from a function expression. there are only 2 ways i know to generate the function that is returned, it could be written similarly to the next code block with the if outside the inner function which would create a lot of code duplication as i would need to write everything in the function that is unchanged again.
function genFunction1(env){
if(env == "env1"){
return function () {return 3;}
}
else{
return function () {return 2;}
}
}
or with the if inside like the following code block
genFunction1(env){
return function (){
if(env=="env1"){
return 3;
}
return 2;
}
}
however if we use a object with a get property which logs when accessed we can see that the third code block calls a if for each call of myFunc1.
function genFunc1(obj){
return function (){
if(obj.env == "env2"){
console.log("3");
}
console.log("2");
}
}
const obj = {
get env() {
console.log("accessed property");
return "env2";
}
}
var myFunc1 = genFunc1(obj);
myFunc1();
myFunc1();
as previously said the earlier code block calls the get method once for each call of myFunc1(),but the environment won't change aside from the first time i check, is there any way to make the generated function not include a if and include the if only in the higher order function without duplicating code?
This is expected behavior as you are getting property from an object. Take a snapshot of the value before generating the function, like this.
function genFunc1(obj) {
var env = obj.env
return function() {
if (env == "env2") {
console.log("3");
}
console.log("2");
}
}
function person1(name) {
var n = name;
return (function (n) {
alert(n);
})(n);
}
person1('susan')();
person1('peter')();
The second statement cannot be run, anyone can give me a correct explanation.
person1('susan') does not return a function, it returns undefined, so you can't call it afterwards - the extra () results in the script throwing.
If you want calling person1 to return a function that, when called, alerts the name, remove the n parameter, and return a function that alerts name - but don't call the function, just return it, so the returned function can be called outside:
function person1(name) {
return () => {
console.log(name);
};
}
person1('susan')();
person1('peter')();
The code of your function is basically ok but the call person1 is not. You should omit the brackets after the call. Because your not returning a function back from person1. Actually you don't have a return value at all.
function person1(name) {
var n = name;
return (function (n) {
alert(n);
})(n);
}
person1('susan');
person1('peter');
This would work but can be simplified.
I don't know how to ask this on google that's why I asked here instead,
The console.log from the getListByElement() function won't execute here,
I am modifying a very large existing project and uses functionality hooks for validation purposes and executes that hook on certain .on events, what I want to know is why the console.log won't get executed,
which gets executed first,
Order of execution on my understanding
1. trigger event function for the field `fieldName`
2. fieldName.functionalityHook = [Apple.functionalityHook()];
3. Apple.functionalityHook = function(func) {
4. return function(e) {
5. getListByElement(ele); and display console.log();
6. return func;
Here is the sample code that I have,
var Apple= window.Apple; // global
fieldName.functionalityHook = [Apple.functionalityHook()];
Apple.functionalityHook = function(func) {
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
}
function getListByElement(ele){
console.log('ele here');
}
Thank You for answering,
as par my understanding your getListByElement() is not invoking because of the function initialization. You are calling the functionalityHook() before its initialization.
fieldName.functionalityHook = [Apple.functionalityHook()];
Apple.functionalityHook = function(func) {..........
and this invocation returning a function
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
and inside this function getListByElement() is calling.
So, the correct code arrangement should be like this.
var Apple= window.Apple;
function getListByElement(ele){
console.log('ele here');
}
Apple.functionalityHook = function(func) {
return function(e) {
var ele = $(e.target);
getListByElement(ele);
return func;
}
}
fieldName.functionalityHook = [Apple.functionalityHook()];
I'm practicing closures and my assigment for now is to :
Write a function once that accepts a callback as input and returns a function.
When the returned function is called the first time, it should call the callback
and return that output. If it is called any additional times, instead of calling
the callback again it will simply return the output value from the first time it
was called.
My callback is:
const addByX = function (num1) {
let number = num1;
function adding(num2) {
console.log(number + num2);
}
return adding;
}
//addByX(2)(8);
let addByTwo = addByX(2);
And my main function is:
const once = function (func) {
let isFirst = true;
let firstOutput;
function inside(numberToPass) {
if (isFirst) {
firstOutput = func(numberToPass);
isFirst = false;
return func(numberToPass);
} else {
return firstOutput;
}
}
return inside;
}
It works, but when I invoke it
const onceFunc = once(addByTwo);
console.log(onceFunc(4)); //should log 6
console.log(onceFunc(10)); //should log 6
it returns my values and also undefined.
And I really can't understand why would it.
Maybe if it works I should not ask this kind of questions, but I'm really curious.
Debugger couldn't clearly answer my question.
I'm suspicious it has something to do with console.log, as abvious as it looks.
Here in JS Bin
The function addByX returns another function, adding. But adding doesn't return anything; it just logs. It's return value is undefined.
I think you intended it to look like this:
const addByX = function (num1) {
let number = num1;
function adding(num2) {
return number + num2;
}
return adding;
}
So the reason that it "worked" is because the callback was printing to the console, rather than where you are invoking it.