I am new to JS, and I have read a code that contains this line.
this.myArray[index](this._sender, args);
I wonder what it means?
It means that this array item is a function, and it is being called with arguments this._sender and args.
In this example, I declare an array, push a single-argument function to it, and call it.
var arr = [];
arr.push(function(str) {
document.body.innerHTML = "Hey, " + str;
});
arr[0]("Your name");
that means that the myArray[index] is the element of myArray that is function that is why it requires 2 arguments.
It is similar to following snippet:
var myClass = function () {
this._a = 5;
var index = arguments[0] || 0;
this.myArray = [
function (a, b) {
console.log(a, b);
},
function (a, b) {
console.log(a, b);
}
];
this.myArray[index](this._a, arguments);
};
var obj = new myClass(1, 2, 3);//5 [1, 2, 3]
In JavaScript, functions are first class objects so they can be passed around/referenced, stored, and accessed like any other value.
var myArray = [];
var myFunction = function(name) {
console.log("Hello, " + name + "!");
};
myFunction('World');
myArray[0] = myFunction;
myArray[0]('again');
function addDefault(func, defaultValue) {
return function(name) {
name = name ? name : defaultValue;
func(name);
}
}
var myFunctionWithDefault = addDefault(myFunction, 'stranger');
myFunctionWithDefault();
myFunctionWithDefault('goodbye');
JSBin: http://jsbin.com/wubuye/edit?js,console
Related
I'm troubleshooting some 3rd party code on a client's website. The client was having issues with the code not working. I found that the issue was related to bound JS functions. Arguments that were passed to the bound function were undefined. I couldn't figure out why. Everything seems fine. However, I then found that the client has overridden the Bind function. Here is what they have:
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
};
};
So if I create a function
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
Then bind that function:
var boundFunction = sumFunction.bind(null, 10);
When I call that bound function I get the following:
console.log(boundFunction(20));
a: 20
b: undefined
NaN
I found a similar SO question that was using the same bind function. javascript custom scope binding function
It appears that it used to work? The SO question I linked seemed to work back in 2013, but now it doesn't form me.
Is this just outdated? JavaScript isn't my main strength, but my client will want to know why their function is causing the problem.
I found the overridden bind function to be odd. Especially the line return _function.apply(scope, arguments); It seems like passing the entire arguments object is incorrect. Shouldn't it only send the arguments in array position 1 and higher? I tried changing that to this to test:
Function.prototype.bind = function(scope) {
var _function = this;
var newArgs = Array.prototype.slice.call(arguments, 1)
return function() {
return _function.apply(scope, newArgs );
};
};
But now I just get the following:
console.log(boundFunction(20));
a: 10
b: undefined
NaN
When the function is bounded, there might be an array of arguments after the 1st, so use slice(1) to get them. When the function is called, get the all the arguments, and concat both args arrays.
Concat both arrays of arguments:
Function.prototype.bind = function(scope) {
var _function = this;
var args1 = Array.prototype.slice.call(arguments, 1);
return function() {
var args2 = Array.prototype.slice.call(arguments, 0);
return _function.apply(scope, args1.concat(args2));
};
};
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
var boundFunction = sumFunction.bind(null, 10);
console.log(boundFunction(20));
However, calling slice on arguments, might cause the V8 engine to skip optimisation on the function. A better way would be to just iterate the arguments manually, and add them to a single array:
Function.prototype.bind = function(scope) {
var args = [];
var _function = this;
for(var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
return function() {
var newArgs = args.slice(0);
for(var i = 0; i < arguments.length; i++) { newArgs.push(arguments[i]); }
return _function.apply(scope, newArgs);
};
};
var sumFunction = function(a, b){
console.log("a: " + a);
console.log("b: " + b);
return a + b;
}
var boundFunction = sumFunction.bind(null, 10);
console.log(boundFunction(20));
So I'm using a constructor like this
const RPNCalculator = function () {
let methods = {
numberList: [],
calc: 0,
push(num) {
this.numberList.push(num);
},
plus() {
for (let i = 0; i <= this.numberList.length; i++) {
console.log('before:' + this.calc);
this.calc = this.calc + this.numberList[i];
}
console.log('after:' + this.calc);
this.numberList = [];
}
};
return methods;
}
const rpnCalculatorInstance = new RPNCalculator;
The fist console.log prints correctly and adds the elements but the second console.log prints NaN. I've used this pattern before with Object.create but for some reason the this.calc variable isn't persisting when using a constructor.
Any help is appreciated!
you can use reduce to sum up an array https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
run snippet below
class RpnCalculator{
constructor(){
this.numberList = [];
this.push = (num) => { this.numberList = [...this.numberList, num ]}
this.sum = () => {return this.numberList.reduce(( a, c) => a + c, 0);}
}
}
const rpnCalculator = new RpnCalculator();
rpnCalculator.push(1)
rpnCalculator.push(2)
rpnCalculator.push(3)
console.log(rpnCalculator.sum());
Apparently with the dataset I was given the last item in the array was an undefined element. I fixed it by using
if (typeof (this.numberList[i]) === 'number') {
console.log('before:' + this.calc);
this.calc = this.calc + this.numberList[i];
}
I wanted to clone original object and function without reference, is my code consider the correct way to clone object and function?
var apple = new function() {
this.type = "macintosh";
this.color = "red";
}
function aaa() {
return this.color + ' ' + this.type + ' apple';
};
var a = JSON.parse(JSON.stringify(apple))
var b =
JSON.parse(JSON.stringify(apple));
console.log(a)
a.getInfo = aaa
b.getInfo = aaa
a.color='green' // only a is green color
console.log(a.getInfo())
console.log(b.getInfo())
Try this function:
var clone = function (object) {
// Copy everything that is not an object
if (object == null || typeof(object) !== 'object') {
return object
}
// Calling constructor
var temp = new object.constructor()
// Recursively cloning children
for (var key in object) {
temp[key] = clone(object[key])
}
return temp
}
Test:
var test = { a: 0, b: function () { console.log(1) } }
var cloned = clone(test)
https://jsfiddle.net/feshcdLe/1/
For cloning objects, you can use Object.assign and set the first argument as an empty object.
For example
const clone = Object.assign({}, apple.call({}));
const result = aaa.call(clone);
console.log(result);
//=> red macintosh apple;
I made use of Function.call here simply because I don't know if you meant to access the global this or a different scope or what. If you do know what your this is referring to, then you can simply do.
const clone = Object.assign({}, this);
const result = aaa();
console.log(result);
MDN Object.assign
MDN Function.call
I am trying to write a function that takes functions as arguments (as many as it gets) and returns them. The function funcArg should return 'Called me'. I used Array.prototype.slice.call(arguments); to create an array but I don't know how to call die functions in that array. Any ideas? Thanks!!
var caller = function() {
return "Called ";
};
var adder = function() {
return " me";
};
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
}
funcArgs(caller);
funcArgs(calleradder);
You can do this using reduce.
var funcArgs = function() {
var functions = Array.prototype.slice.call(arguments);
return functions.reduce(function(total, f) {
return total + f();
}, '');
};
The way this works if you start off with an array of functions. We then go through each function one at a time. We then call that function and append it to the result of the previous function. Breaking this down into simpler code would look like this:
var funcArgs = function() {
var functions = [caller, adder];
var result = '';
result += functions[0](); // caller();
result += functions[1](); // adder();
return result;
};
If you have an array of functions you can loop over them with forEach.
var caller = function() {
return "Called "
}
var adder = function() {
return " me"
}
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
myArray.forEach(function (fn) {
console.log(fn())
})
}
funcArgs(caller, adder); // "Called me"
If you want to actually return the values, rather than just console.log them, you can use reduce to return the strings concatenated (or whatever else)
var funcArgs = function() {
var myArray = Array.prototype.slice.call(arguments);
return myArray.reduce(function (acc, fn) {
return acc + fn()
}, '')
}
var object = {}; //lots of stuff in here
var func = object.dosome;
object.dosome = function(a,b) {
func(a,b);
//someth else here i need to add
}
This works but ugly.
So is there a way to supplement object.dosome method, without creating a new variable containing it's function?
Some sort of parent.dosome?
maybe create a class Object and define in its protoype the dosome() method.
var Object = new function() {}; //lots of stuff in here
Object.prototype.dosome = function(a,b) {
func(a,b);
}
//and then
var myObject = new Object();
I think you should read a little about JS OOP. ES6 adds some nice syntactic sugar that can help you achieve what you want in fewer lines of code. Read more here.
However, if you don't want to have problems with the prototype chains, here's a simpler way of achieving what you want:
function chain (baseFunc, func) {
return function () {
var args = [].slice.call(arguments, 0);
args.unshift(baseFunc);
return func.apply(this, args);
};
}
Usage:
var obj = {
doSome: function (a, b) { return a + b; }
};
obj.doSome(4, 5); // 9
obj.doSome = chain(obj.doSome, function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 10;
});
obj.doSome(4, 5); // 19
You can go one step further and get rid of the assignment:
function extend (instance, method, func) {
instance[method] = chain(instance[method], func);
}
extend(obj, "doSome", function (baseFunc, a, b) {
var result = baseFunc(a, b);
return result + 2;
});
obj.doSome(4, 5); // 21