Preserving the function's scope when using function.apply(...) - javascript

Consider the following example:
var funcToCall = function() {...}.bind(importantScope);
// some time later
var argsToUse = [...];
funcToCall.apply(someScope, argsToUse);
I want to preserve 'importantScope' of funcToCall. Yet, I need to use apply to apply an unknown number of arguments. 'apply' requires that I provide 'someScope'. I don't want to change the scope, I just want to apply the arguments to the function and preserve its scope. How would I do that?

You can pass any old object (including null) as the first argument to the apply() call and this will still be importantScope.
function f() {
alert(this.foo);
}
var g = f.bind( { foo: "bar"} );
g(); // Alerts "bar"
g.apply(null, []); // Alerts "bar"
The bind method creates a new function in which the this value is guaranteed to be the object you passed in as the parameter to the bind call. Regardless of how this new function is called, this will always be the same. A simple implementation would look like this (note the implementation specified ECMAScript 5 and that in Prototype does more than this but this should give you the idea):
Function.prototype.bind = function(thisValue) {
var f = this;
return function() {
return f.apply(thisValue, arguments);
};
};

Related

Can you rebind a rebound function using `bind`

bind method creates a new function that when called has its this keyword set to the provided value.
var obj = {
a: 0,
b() {
console.log(this.a);
}
}
obj.b() // -> 0
var functionBound = obj.b.bind(obj)
functionBound() // -> 0
functionBound.bind(null)() // -> 0 AND I expect an error here
Clearly, I cannot rebind a function has already been rebound. However, I could not find any documentation on this behavior.
Quote from "Bind more arguments of an already bound function in Javascript"
Once you bound an object to a function with bind, you cannot override it. It's clearly written in the specs, as you can see in MDN documentation:
The bind() function creates a new function (a bound function) with the same function body (internal call property in ECMAScript 5 terms) as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(), which cannot be overridden.
I could not find these in MDN documentation. I did an exact full-text search on the quote above on Google and seems the SO answer above is the only source for this behavior. I also try to find an answer in the language spec with no luck.
My question is do you know this behavior and where can I find any official documentation on these?
This may not directly answer the question about getting a officially documented specification validating this behavior, but we can base our conclusions on the source code provided in MDN, specifically in the documentation for Function.prototype.bind(), under section Polyfill, where they provide an example of how a polyfill bind function would look like.
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
}
We can see that the oThis parameter is used in the closure fBound which is the one ultimately returned by the bind function.
This means that when you invoke the bind function, you get a closure function in return which, when invoked, accesses the oThis free variable provided as parameter in the original invocation of bind.
As such, it doesn't matter how many more times you rebind the bound fBound function, this function is already bound forever to the original context oThis within its closure.
The MDN documentation also points to Raynos bind implementation for further reference, which seems to correspond to this example as well.
The problem is that Function.prototype.bind returns a NEW function instead of the same. Calling a bound function with a different this-argument has no effect, because the bound function already knows which value to use as the this-argument.
You could use this for binding your functions:
Function.boundOriginProp = Symbol()
Function.prototype.bindDynamic = thisArg => {
let origin = this[Function.bindOriginProp] || this
let bound = (...args) => origin.call(thisArg, ...args)
bound[Function.bindOriginProp] = origin
return bound
}
So you can rebind functions that have already been bound like this:
let obj1 = { value: 1 }
let obj2 = { value: 2 }
function example() {
console.log(this.value)
}
let fn1 = example.bindDynamic(obj1)
fn1() // -> 1
let fn2 = fn1.bindDynamic(obj2)
fn2() // -> 2
let fn3 = fn1.bindDynamic(null)
fn3() // -> undefined
I hope this can help you ;)
The bind method wraps the original function and creates a new Bounded Function.
Actually, a function which wraps the original function keeping the same body of the original function.
This is the definition in the MDN website:
The bind() function creates a new bound function (BF). A BF is an
exotic function object (a term from ECMAScript 2015) that wraps the
original function object. Calling a BF generally results in the
execution of its wrapped function.
So, every time you call .bind, you create a new function passing the context as first parameter and the args as rest of parameters, but keeping the body of the first definition.
You can also override the initial body, and bind the function again.
At the same time, you can also take a previously bounded function and bind it again to a new function.
In the following example, you should see the expected behavior:
var printer = function(a) {
console.log(a);
};
var printer1 = printer.bind(null, 1);
var printer2 = printer.bind(null, 2);
var printer3 = printer.bind(null, 3);
printer1();
printer2();
printer3();
printer = function(a) {
console.log("I am a new " + a);
};
var printer4 = printer.bind(null, 4);
printer4();
var newPrinter = function() {
console.log('I am a new printer!');
}
printer4 = newPrinter.bind(null);
printer4();

When creating an instance of a Javascript "class," is there a way to structure the object such that all methods may be accessed?

Is there a way to create an object in Javascript such that all of its methods are available to the constructor?
I'm finding it tough to phrase my problem clearly.. so an example!
Given this class
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
verifySomething(); <-- Fails!
this.verifySomething = function() {
// do verify stuff
}
}
I can't call verifySomething in my constructor because the method, as far as the instance is concerned, doesn't exist yet. So, I get an undefined error. Is there a better way to create objects in javascript so that I can avoid this problem?
Is there a way to create an object in Javascript such that all of its methods are available to the constructor?
You can call any method once it's been created. In your example, there are two issues:
You haven't created the method yet
You are calling it incorrectly — in JavaScript, using the object qualifier (this. within a constructor, usually) isn't optional as it is in some other languages
If you define methods on the constructor function's prototype property, provided those assignments happen before the call to the constructor (which is usually true, and there are techniques for guaranteeing it), the methods will be available on this within the constructor. If you create methods within the constructor (as in your example), just create them first.
Here's your example using the constructor's prototype property, which refers to the object that will be used as the prototype of instances created via new:
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething(); // <== Works
}
Example.prototype.verifySomething = function() {
// do verify stuff
};
var e = new Example();
Here's an example defining within the constructor that makes use of the fact that function declarations (rather than expressions) are "hoisted" (completed before any step-by-step code runs).
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething = verifySomething; // <== Note we assign first
this.verifySomething(); // <== Works
function verifySomething() {
// do verify stuff
}
}
var e = new Example();
If you really don't like doing that assignment before calling it, you could use .call:
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
verifySomething.call(this); // <== Works
// this.verifySomething(); // <== Would not work
this.verifySomething = verifySomething; // <== Note we assign after
function verifySomething() {
// do verify stuff
}
}
var e = new Example();
I mentioned above that there are techniques for guaranteeing that the prototype property of the constructor function has been fully fleshed-out before the constructor is ever called. Here's one of them (using a scoping function):
var Example = (function() {
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething(); // <== Works
}
Example.prototype.verifySomething = function() {
// do verify stuff
};
return Example;
})();
var e = new Example();
With the above, there's no way code outside the containing immediately-invoked scoping function can use Example until after that scoping function has finished, and therefore fully set up the prototype property.

method invocation pattern vs function invocation pattern

Reading JavaScript Good Parts, I come across two patterns to call a function:
// Method Invocation
var myObject = {
value: 0;
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment( );
document.writeln(myObject.value); // 1
myObject.increment(2);
document.writeln(myObject.value); // 3
// Function Invocation
myObject.double = function ( ) {
var that = this; // Workaround.
var helper = function ( ) {
that.value = add(that.value, that.value)
};
helper( ); // Invoke helper as a function.
};
// Invoke double as a method.
myObject.double( );
document.writeln(myObject.getValue( )); // 6
The method invocation pattern makes sense. However, in the function invocation pattern, he says "When a function is not the property of an object, then it is invoked as a function". Well wait a second, isn't the double function a property of myObject? I assume here that myObject is an object literal although it doesn't show its initialization in text. So if it is an object literal, then there is no difference between the two patterns. All we are doing is augmenting a value to the literal. Further, does anyone know where this getValue() is coming from?
I know that these two are indeed distinct in some way, since this in function invocation refers to global context in function invocation, whereas it refers to object itself in method invocation pattern.
The difference is in how the this keyword works inside a function. The odd interesting thing is that in JavaScript it doesn't depend on how the function is defined, but how it is called:
If the function is called as helper(), you cannot use this (with a meaningful value) in the helper code.
If the function is called as myObject.double(), we call that a "method invocation", and this in the double code is the myObject as expected.
This example in the book really confused me for some reason. I reworked his example to better match his explanation (IMHO)
var myObject = {
value: 1,
double: function() {
that = this;
var inner = function() { that.value = that.value + that.value; };
inner(); // Functional invocation
}
};
myObject.double(); // Method invocation
console.log(myObject.value);
Method Pattern
The double method is invoked using the method pattern, therefore this is bound to myObject
Functional Pattern
The inner method is invoked using the functional pattern, therefore this is bound to the global object instead of myObject
Notice the lack of affect on the value property if you modify the double method as follows:
double: function() {
var inner = function() { this.value = this.value + this.value; };
inner();
}

On Javascript, why is a function that is not bound using bind() still binds to the object?

In the following code, the first function is not bound to obj, but the second function is, so f() returns fifi and g() returns Mark Twain as expected. But the 3rd attempt, it is by (obj.getCallBack) first, which is now a function, and then it is invoked, essentially it should be the same as the f case. But they do print out Mark Twain instead. Why are they not bound to obj using bind() but still got executed with this pointing to obj?
(the 4th attempt is just a usual invocation of a method, and this should bind to the object on which the method is invoked on).
(tested on the current Chrome, Firefox, and IE 9)
window.name = "fifi";
var obj = {
name: "Mark Twain",
getCallBack: function() {
return this.name;
}
}
var f = obj.getCallBack;
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack)());
console.log(obj.getCallBack());
You are forgetting that if a function is called as a property of some object, that object will be the this for the call. So:
obj.getCallBack() //The function referenced by `obj.getCallBack`
//is called as a property of `obj`, so obj will be `this`
//for the call
f() //The function referenced by f, is not called as a property of some object so
//`this` will depend on strict mode.
After these basic rules, the bound function will be invoked, which can be thought of as a proxy function (any shim does this) that uses .call/.apply to explicitly set the context for the target function. So the this value for the proxy function doesn't matter, but behind the scenes it was set by the basic rules.
Edit:
(obj.getCallBack) does not return the function as value, because getValue is not called.. So it is exactly the same as obj.getCallback and the first post applies.
So you can do this and not get an error:
(obj.getCallback) = 5;
As opposed to:
(function(){}) = 5; //invalid assignment
To complement Esailija's answer, the desired effect actually should be:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return function() { return this.name; };
}
}
var f = obj.getCallBack();
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack())());
console.log(obj.getCallBack()());
console.log(obj.getCallBack().bind(obj)());
Then in this case, the third attempt will give fifi, and so will the 4th attempt. To get the name inside obj, the fifth attempt binds it and invoke it and will get Mark Twain.
But the method that returns the callBack function should bind it, so let's change the code to:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return (function() { return this.name;}).bind(this); // <-- note here
}
}
and now all attempts, even f(), will return Mark Twain.

jQuery-style function that can be accessed like an object

I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"

Categories

Resources