Understanding the code of _.bind - javascript

This is the code for _.bind, taken from the Underscore library. I don't understand the business of taking the empty function, changing it's prototype, etc.
var ctor = function(){};
_.bind = function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};

It basically is there so that if you call new bound(), you're able to bind arguments for the new call. E.g.:
var func = function(a, b) {
this.a = a;
this.b = b;
};
// context does not matter, use e.g. `null`
var bound = _.bind(func, null, 1);
new bound(2); // a = 1, b = 2
I tried to explain the code a bit.
var ctor = function(){};
_.bind = function bind(func, context) {
var bound, args;
// use native .bind if available
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
// abort if not called with a function
if (!_.isFunction(func)) throw new TypeError;
// you can also bind arguments, which come after the function and context (so .slice(2))
args = slice.call(arguments, 2);
// return the bound function
return bound = function() {
// if you simply do bound(), then `this` is the global object.
// This means the original function should be called with the
// bound `this` value and arguments. Arguments you pass to the
// bound function are concatenated to the bound arguments.
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
// otherwise, you're calling like `new bound()`, because `this instanceof bound`.
// In that case, `this` should not be passed, but only the arguments. So, you
// create a function of which the prototype is the original function's prototype,
// and create an instance of it (to mimic `new func`).
ctor.prototype = func.prototype;
var self = new ctor; // won't execute anything since ctor's body is empty.
// Just creates an instance
// then, you call the original function with the `this` value of the instance,
// with bound arguments and new arguments concatenated. This way, the constructor
// (func) is executed on the instance.
var result = func.apply(self, args.concat(slice.call(arguments)));
// finally, return the result if it's an object (the specs say `new xxx` should
// return an object), otherwise return the instance (like you would with `new func`)
if (Object(result) === result) return result;
return self;
};
};

Related

how to change arguments of caller function by Function.prototype.apply()?

function foo1(a,b){
console.log(arguments); //["oldValue","oldValue"]
var newArguments = foo2.apply(this,arguments);
for (var i=0;i<arguments.length;i++){
arguments[i] = newArguments[i];
}
console.log(arguments); //["newValue","newValue"]
}
function foo2(){
arguments[0] = "newValue";
arguments[1] = "newValue";
console.log(arguments); //["newValue","newValue"]
return arguments;
}
foo1("oldValue","oldValue");
I'd like to change foo1 arguments values by outer function foo2. I did it by returning array with new arguments in foo2 and replacing foo1 arguments with returned array in foo1. Is there any other - more elegant - way to do so?
https://jsbin.com/jibodu/1/edit?js,console
If you're returning the two new arguments from foo2 just set the arguments to that return value:
arguments = foo2();
full code:
function foo1(a,b){
console.log(arguments); //["oldValue","oldValue"]
arguments = foo2();
var newArguments = foo2.apply(this,arguments);
for (var i=0;i<arguments.length;i++){
arguments[i] = newArguments[i];
}
console.log(arguments); //["newValue","newValue"]
}
Why don't you receive the arguments directly?
function foo1() {
console.log('foo1', arguments); // foo1 { '0': 'oldValue', '1': 'oldValue' }
arguments = foo2.apply(this, arguments);
console.log('foo1', arguments); // foo1 { '0': 'newValue', '1': 'newValue' }
}
function foo2() {
arguments[0] = 'newValue';
arguments[1] = 'newValue';
console.log('foo2', arguments); // foo2 { '0': 'newValue', '1': 'newValue' }
return arguments;
}
foo1('oldValue', 'oldValue');
Update 1
Since you want to change a, b also, I would try calling foo1 "again" like below:
function foo1(a, b) {
console.log('foo1', arguments);
if (a === 'oldValue') // Detect if `arguments` has been changed or not.
// (You can also use a variable to record the change if you prefer.)
// If not, change the arguments and call `foo1` using the new arguments
return foo1.apply(this, foo2.apply(this, arguments));
console.log('foo1 (after changed)', arguments , a, b);
// Do something you want to do originally in `foo1`
}
I suppose that you can make a new function instead of change the arguments inside the foo1, since it seems a little tricky to me?
ok I found resolution. I've just changed first parameter in apply() to "arguments". Now it refers to arguments of caller function and by 'this' I can directly change its values. nonetheless thanks for support!
function foo1(a, b) {
foo2.apply(arguments,arguments);
console.log(arguments); //["newValue","newValue"]
console.log(a); //"newValue"
}
function foo2() {
this[0] = "newValue";
this[1] = "newValue";
};
foo1("oldValue","oldValue");

What happens if construction function returns new Func()

When I write
function abc() {
return 3;
}
var t = new abc();
console.log(t); // abc {}
However when i do this
function a() {
this.name = 'test';
}
function b() {
this.age = 33;
return new a();
}
var p = new b();
console.log(p); // a { name = 'test'}
So In first example, why does it return an object when return is actually returning a number. And when i do return new Func() .... i get the new Obj.. the returned value.
In one scenario i get returned value, in other the main obj.
That's as per ES5.1 specification 13.2.2 [[Construct]]
Relevant part:
Let result be the result of calling the [[Call]] internal property of
F, providing obj as the this value and providing the argument list
passed into [[Construct]] as args.
If Type(result) is Object then return result.
Return obj.
The similar part from the ES2015: 9.2.2 [[Construct]] ( argumentsList, newTarget)
Let result be OrdinaryCallEvaluateBody(F, argumentsList).
Remove from the execution context stack and restore
callerContext as the running execution context.
If result.[[type]] is return, then
If Type(result.[[value]]) is Object, return NormalCompletion(result.[[value]]).
If kind is "base", return NormalCompletion(thisArgument).
If result.[[value]] is not undefined, throw a TypeError exception.
Thanks to #Barmar for the summary:
In other words, if the constructor returns an object, new returns that object, otherwise it returns this
This constructor is okay:
function foo() {
// will set attribute on new object
this.age = 33;
}
t = new foo;
Object.getPrototypeOf(t); // foo
This one as well:
function bar() {
// delegates construction to other method
// object will not have prototype bar, but prototype baz
return new baz();
}
t = new bar;
Object.getPrototypeOf(t); // baz
But this constructor will not do what most people expect:
function b() {
this.age = 33;
// because you are returning a different object;
// that other object will not have its .age attribute set
// by the statements above.
// object will not have prototype b, but prototype a
return new a();
}
t = new b;
Object.getPrototypeOf(t); // a
You could however do the following:
function b() {
var o = new a();
o.age = 33;
// object will not have prototype b, but prototype a
return o;
}
t = new b;
Object.getPrototypeOf(t); // a

How to bind function arguments without binding this?

In Javascript, how can I bind arguments to a function without binding the this parameter?
For example:
//Example function.
var c = function(a, b, c, callback) {};
//Bind values 1, 2, and 3 to a, b, and c, leave callback unbound.
var b = c.bind(null, 1, 2, 3); //How can I do this without binding scope?
How can I avoid the side-effect of having to bind the function's scope (e.g. setting this = null) as well?
Edit:
Sorry for the confusion. I want to bind arguments, then be able to call the bound function later and have it behave exactly as if I called the original function and passed it the bound arguments:
var x = 'outside object';
var obj = {
x: 'inside object',
c: function(a, b, c, callback) {
console.log(this.x);
}
};
var b = obj.c.bind(null, 1, 2, 3);
//These should both have exact same output.
obj.c(1, 2, 3, function(){});
b(function(){});
//The following works, but I was hoping there was a better way:
var b = obj.c.bind(obj, 1, 2, 3); //Anyway to make it work without typing obj twice?
I'm still new at this, sorry for the confusion.
Thanks!
You can do this, but best to avoid thinking of it as "binding" since that is the term used for setting the "this" value. Perhaps think of it as "wrapping" the arguments into a function?
What you do is create a function that has the desired arguments built into it via closures:
var withWrappedArguments = function(arg1, arg2)
{
return function() { ... do your stuff with arg1 and arg2 ... };
}(actualArg1Value, actualArg2Value);
Hope I got the syntax right there. What it does is create a function called withWrappedArguments() (to be pedantic it is an anonymous function assigned to the variable) that you can call any time any where and will always act with actualArg1Value and actualArg2Value, and anything else you want to put in there. You can also have it accept further arguments at the time of the call if you want. The secret is the parentheses after the final closing brace. These cause the outer function to be immediately executed, with the passed values, and to generate the inner function that can be called later. The passed values are then frozen at the time the function is generated.
This is effectively what bind does, but this way it is explicit that the wrapped arguments are simply closures on local variables, and there is no need to change the behaviour of this.
In ES6, this is easily done using rest parameters in conjunction with the spread operator.
So we can define a function bindArgs that works like bind, except that only arguments are bound, but not the context (this).
Function.prototype.bindArgs =
function (...boundArgs)
{
const targetFunction = this;
return function (...args) { return targetFunction.call(this, ...boundArgs, ...args); };
};
Then, for a specified function foo and an object obj, the statement
return foo.call(obj, 1, 2, 3, 4);
is equivalent to
let bar = foo.bindArgs(1, 2);
return bar.call(obj, 3, 4);
where only the first and second arguments are bound to bar, while the context obj specified in the invocation is used and extra arguments are appended after the bound arguments. The return value is simply forwarded.
In the native bind method the this value in the result function is lost. However, you can easily recode the common shim not to use an argument for the context:
Function.prototype.arg = function() {
if (typeof this !== "function")
throw new TypeError("Function.prototype.arg needs to be called on a function");
var slice = Array.prototype.slice,
args = slice.call(arguments),
fn = this,
partial = function() {
return fn.apply(this, args.concat(slice.call(arguments)));
// ^^^^
};
partial.prototype = Object.create(this.prototype);
return partial;
};
var b = function() {
return c(1,2,3);
};
One more tiny implementation just for fun:
function bindWithoutThis(cb) {
var bindArgs = Array.prototype.slice.call(arguments, 1);
return function () {
var internalArgs = Array.prototype.slice.call(arguments, 0);
var args = Array.prototype.concat(bindArgs, internalArgs);
return cb.apply(this, args);
};
}
How to use:
function onWriteEnd(evt) {}
var myPersonalWriteEnd = bindWithoutThis(onWriteEnd, "some", "data");
It's a bit hard to tell exactly what you ultimately want to do because the example is sort of arbitrary, but you may want to look into partials (or currying): http://jsbin.com/ifoqoj/1/edit
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
var c = function(a, b, c, callback) {
console.log( a, b, c, callback )
};
var b = c.partial(1, 2, 3, undefined);
b(function(){})
Link to John Resig's article: http://ejohn.org/blog/partial-functions-in-javascript/
Using LoDash you can use the _.partial function.
const f = function (a, b, c, callback) {}
const pf = _.partial(f, 1, 2, 3) // f has first 3 arguments bound.
pf(function () {}) // callback.
May be you want to bind reference of this in last but your code:-
var c = function(a, b, c, callback) {};
var b = c.bind(null, 1, 2, 3);
Already applied binding for instance this and later you can not change it.
What I will suggest that use reference also as a parameter like this:-
var c = function(a, b, c, callback, ref) {
var self = this ? this : ref;
// Now you can use self just like this in your code
};
var b = c.bind(null, 1, 2, 3),
newRef = this, // or ref whatever you want to apply inside function c()
d = c.bind(callback, newRef);
Use a protagonist!
var geoOpts = {...};
function geoSuccess(user){ // protagonizes for 'user'
return function Success(pos){
if(!pos || !pos.coords || !pos.coords.latitude || !pos.coords.longitude){ throw new Error('Geolocation Error: insufficient data.'); }
var data = {pos.coords: pos.coords, ...};
// now we have a callback we can turn into an object. implementation can use 'this' inside callback
if(user){
user.prototype = data;
user.prototype.watch = watchUser;
thus.User = (new user(data));
console.log('thus.User', thus, thus.User);
}
}
}
function geoError(errorCallback){ // protagonizes for 'errorCallback'
return function(err){
console.log('#DECLINED', err);
errorCallback && errorCallback(err);
}
}
function getUserPos(user, error, opts){
nav.geo.getPos(geoSuccess(user), geoError(error), opts || geoOpts);
}
Basically, the function you want to pass params to becomes a proxy which you can call to pass a variable, and it returns the function you actually want to do stuff.
Hope this helps!
An anonymous user posted this additional info:
Building on what has already been provided in this post -- the most elegant solution I've seen is to Curry your arguments and context:
function Class(a, b, c, d){
console.log('#Class #this', this, a, b, c, d);
}
function Context(name){
console.log('#Context', this, name);
this.name = name;
}
var context1 = new Context('One');
var context2 = new Context('Two');
function curryArguments(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function bindContext() {
var additional = Array.prototype.slice.call(arguments, 0);
return fn.apply(this, args.concat(additional));
};
}
var bindContext = curryArguments(Class, 'A', 'B');
bindContext.apply(context1, ['C', 'D']);
bindContext.apply(context2, ['Y', 'Z']);
Well for the exemple you gave, this will do
var b= function(callback){
return obj.c(1,2,3, callback);
};
If you want to guarenty enclosure of the parameters :
var b= (function(p1,p2,p3, obj){
var c=obj.c;
return function(callback){
return c.call(obj,p1,p2,p3, callback);
}
})(1,2,3,obj)
But if so you should just stick to your solution:
var b = obj.c.bind(obj, 1, 2, 3);
It's the better way.
Simple like that?
var b = (cb) => obj.c(1,2,3, cb)
b(function(){}) // insidde object
More general solution:
function original(a, b, c) { console.log(a, b, c) }
let tied = (...args) => original(1, 2, ...args)
original(1,2,3) // 1 2 3
tied(5,6,7) // 1 2 5
I'm using this function:
function bindArgs(func, ...boundArgs) {
return function (...args) {
return func(...boundArgs, ...args);
};
}
// use
const deleteGroup = bindArgs(this.props.deleteGroup, "gorupName1");
Why not use a wrapper around the function to save this as mythis ?
function mythis() {
this.name = "mythis";
mythis = this;
function c(a, b) {
this.name = "original";
alert('a=' + a + ' b =' + b + 'this = ' + this.name + ' mythis = ' + mythis.name);
return "ok";
}
return {
c: c
}
};
var retval = mythis().c(0, 1);
jQuery 1.9 brought exactly that feature with the proxy function.
As of jQuery 1.9, when the context is null or undefined the proxied function will be called with the same this object as the proxy was called with. This allows $.proxy() to be used to partially apply the arguments of a function without changing the context.
Example:
$.proxy(this.myFunction,
undefined /* leaving the context empty */,
[precededArg1, precededArg2]);
Jquery use case:
instead:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(i){
$(this).val(i); // wont work, because 'this' becomes 'i'
}.bind(i));
}
use this:
for(var i = 0;i<3;i++){
$('<input>').appendTo('body').click(function(e){
var i = this;
$(e.originalEvent.target).val(i);
}.bind(i));
}

Accessing parent function when using Function.prototype methods

I'm playing around with Function.prototype as a learning exercise and was trying to make a generic curry method that could be used like this:
// Any old function
var myFn = function(arg1, arg2) {
console.log(arg1, arg2);
};
// Curry some parameters and return a new function
var myFnCurry = myFn.curry("A");
// Call the curried function, passing in the remaining parameters
myFnCurry("B"); // Outputs: A B
It's fairly straight forward to implement this feature as a function rather than a method using the following approach:
var curry = function(fn) {
var slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
fn.apply(this, args.concat(slice.call(arguments)));
};
};
// Example
var myFnCurry = curry(myFn, "A");
myFnCurry("B"); // Outputs: A B
However, I really wanted to be able to utilise the Function prototype, like this:
Function.prototype.curry = function() {
var slice = Array.prototype.slice,
args = slice.call(arguments);
return function() {
// If we call curry like this: myFn.curry()
// how can we get a reference myFn here?
???.apply(this, args.concat(slice.call(arguments)));
};
};
I'm not sure how to get a reference to the myFn function (denoted by the ??? above) that the curry method is being called from.
Is there a way to access the parent function in this circumstance?
Cheers,
Ian
You're calling curry in a context of your function object (myFn.curry), and therefore inside of curry this refers to that function. But your inner function will be called in the context of global object, that's why you need to store the reference to the outer function in a closure.
Function.prototype.curry = function() {
var self = this, args = [].slice.call(arguments)
return function() {
return self.apply(this, args.concat([].slice.call(arguments)));
}
}

How do I create a child class of Javascript's Function class?

I would like to create a Javascript class that I can use like so:
var f = new myFunction(arg1, arg2);
f.arg1; // -> whatever was passed as arg1 in the constructor
f();
f instanceof myFunction // -> true
typeof f // -> function
I can treat it like a normal object, even adding the native Function object to the prototype chain, but I can't call it like a function:
function myFunction(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
myFunction.prototype = Function
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // TypeError: f is not a function, it is object.
f instanceof myFunction // -> true
typeof f // -> object
I can have the constructor return a function, but then it's not an instance of myFunction:
function myFunction(arg1, arg2) {
var anonFunction = function() {
};
anonFunction.arg1 = arg1;
anonFunction.arg2 = arg2;
return anonFunction;
}
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // ok
f instanceof myFunction // -> false
typeof f // -> function
Any suggestions? I should add that I really want to avoid using new Function() since I hate string code blocks.
First and foremost, you should probably be considering some other way of doing this, because it is unlikely to be portable. I'm just going to assume Rhino for my answer.
Second, I'm not aware of any way in Javascript of assigning a function's body after construction. The body is always specified as the object is constructed:
// Normal function definitions
function doSomething() { return 3 };
var doSomethingElse = function() { return 6; };
// Creates an anonymous function with an empty body
var doSomethingWeird = new Function;
Now, there's a non-standard Mozilla extension in the form of a __proto__ property on every object. This allows you the change the inheritance chain of any object. You can apply this to your function object to give it a different prototype after construction:
// Let's define a simple prototype for our special set of functions:
var OddFunction = {
foobar: 3
};
// Now we want a real function with this prototype as it's parent.
// Create a regular function first:
var doSomething = function() {
return: 9;
};
// And then, change it's prototype
doSomething.__proto__ = OddFunction;
// It now has the 'foobar' attribute!
doSomething.foobar; // => 3
// And is still callable too!
doSomething(); // => 9
// And some of the output from your example:
doSomething instanceof OddFunction; // => true
typeof doSomething; // => function
function Foo() { var o = function() {return "FOO"}; o.__proto__ = Foo.prototype; return o; }
(new Foo()) instanceof Foo: true
(new Foo())(): FOO
This isn't possible. If it should be a instance of your function then it has to be a object. Why do you want this?
I dont know why you would want to do something like this. But here's a snippet which comes close,
function MyFunction(arg1, arg2)
{
this.firstProp = arg1;
this.secondProp = arg2;
}
var f = function(arg1, arg2) {
return new MyFunction(arg1, arg2);
}(12,13);
alert("Arg1 " + f.firstProp) // 12;
alert("Arg2 " + f.secondProp) // 13;
alert(f instanceof MyFunction) // true;
Here is what I think a more javascript way of doing what you want, except it doesn't use the instanceof for objects but an inner one.
var f = function(arg1, arg2){
return {
instanceOf:arguments.callee,
arg1:arg1,
arg2:arg2
};
};
var fn = f(1, function(p){ alert(p); });
fn.arg1; // 1
fn.instanceOf === f; //true
typeof f; //function
typeof fn; //object
fn.arg2('hello'); //show alert hello

Categories