retrieve bound object of a function in javascript - javascript

Is there any way to retrieve the object, that is bound to a function as thisArg?
Like:
let object = {};
let fn = function () {
return 'hello world';
}
fn = fn.bind(object);
//now i want a way to achieve that this comparison results in true
let result = (object === fn.getBoundThis());

No, there's nothing built into JavaScript that provides that information. fn itself would need to provide it.

This approach can be helpful if you are able to modify fn function definition. Otherwise I don't see any way to get it.
let object = {a:10};
let fn = function () {
getThisVal(this);
return;
}
let theObject;
let getThisVal = function(val){
theObject = val
}
fn = fn.bind(object);
fn();
console.log(theObject);
One more way can be instead of returning this you can call any other function defined by you inside fn and pass this as parameter and access it there.

Like other answers mention, there is no built-in way.
But you can wrap the bind method and intercept the bound object:
// this should be the first javascript
// that you execute on the page
(function() {
let originalBind = Function.prototype.bind;
//wrap bind function
Function.prototype.bind = function(obj) {
let boundFunction = originalBind.call(this, obj);
boundFunction.boundThis = obj;
return boundFunction;
}
console.warn('`Function.prototype.bind` has been patched!');
})();
function foo() {
console.log(this);
}
let object = {
a: 'bind me'
};
let bar = foo.bind(object);
console.log('\'this\' object of bar: ', bar.boundThis);
console.log(`(object === bar.boundThis) =>`, object === bar.boundThis);
Note: Only the objects created after patching will have boundThis property.

Related

Method chaining within a javascript closure module

Here's a question for js gurus. I'd like to enable method chaining in a js module coded as follows. I'd also like for each method to be able to return an object literal of various values. In the context of how this is coded, how would I enable the function chaining such as method2().method3()
Thanks!
var module1Constructor = (function() {
// methods:
var init = function() {
var someValue = 'value';
method2().method3(); // chained method calls
return {module1:'iDontKnow',returnedValue1:someValue}; // how to pass value back to enable function chaining?
}; // init
var method2 = function() {
var someValue = 'value';
return {module1:'iDontKnow',returnedValue1:someValue}; // how to pass value back to enable function chaining?
}; // method2
var method3 = function() {
var someValue = 'value';
return {module1:'iDontKnow',returnedValue1:someValue}; // how to pass value back to enable function chaining?
}; // method3
return function module1Constructor() {
this.init = init;
} // return function module1Constructor() {
})(); // module1Constructor
var module1 = new module1Constructor;
module1.init();
How is method chaining necessary if it isnt accessible by the user?
So you may want to write onto the prototype of a function, making it a regular constructor:
function module1Constructor(){
//...
}
module1Constructor.prototype={
test:1,
a:function(){
alert(this.test++);
return this;
},
//extended
b:function(){
return Object.assign(new module1Constructor(),this,{c:alert});
}
};
Use like this:
test=new module1Constructor().a().a().a().a();
test.a().c();//doesnt work
test.a().b().c();//does work
test.a().b().a();
The term method chaining is more related to prototypes, in this case, what I see in your comments is you want to access values within functions, that is called closure, which is a way to access a value when a function is invoked outside it's lexical scope. so in your object literal that you are returning, you can do.
var method2 = function() {
var someValue = 'value';
return {module1:'iDontKnow',returnedValue1:someValue, method3:method3};
}

Re: A JavaScript Fn that accepts unknown # args - call Fn wrks - call via var does not

Learning how to write JS Fn that accepts an unknown number of arguments.
function foo(a,b,c,d){
//do something
//return something
}
var bar = function () {
var arg = Array.from(arguments);
var lastIndx = arg.length;
var parArray = arg.slice(1,lastIndx);
var argMnts = arguments[0];
return arguments[0].apply(this, parArray);
};
calling bar thus works:
bar(foo,1,4,3,7);
calling it like so:
var tester = bar(foo,1,4,3,7);
tester();
results in: tester is not a function
From my research I suspected it might have to do with the scope of "this" or arguments so I assigned their values to variables, subbed the vars, and the result was the same.
Some insight would be immensely appreciated.
In your example, calling bar() returns whatever the results of calling foo(...) is. So, if you want to be able to do this:
var tester = bar(foo,1,4,3,7);
tester();
Then, foo(...) has to return another function that can get assigned to tester and can then get called again.
If, instead of the way it is above, if you don't want bar(foo, ...) to actually call foo(), but want it to return a function that will then call foo() with the appropriate arguments, you can change bar() to this:
var bar = function () {
var args = Array.from(arguments);
var fn = args.shift();
var self = this;
return function() {
return fn.apply(self, args);
}
};
var tester = bar(foo,1,4,3,7);
tester();
Here, bar() returns a function, that (when called) will call foo().
Or, with the right ES6 support, you could use rest parameters;
var bar = function (fn, ...args) {
var self = this;
return function() {
return fn.apply(self, args);
}
};
or, you could use .bind() with rest parameters and the spread operator:
var bar = function (fn, ...args) {
return fn.bind(this, ...args);
};

Is it possible to call function.apply without changing the context?

In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this, args);
}
The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(<otherFn's original context>, args);
}
Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.
class Client
constructor: (socket) ->
#socket = socket
#avatar = socket.handshake.avatar
#listeners = {}
addListener: (name, handler) ->
#listeners[name] ||= {}
#listeners[name][handler.clientListenerId] = wrapper = =>
# append client object as the first argument before passing to handler
args = Array.prototype.slice.call(arguments)
args.unshift(this)
handler.apply(this, args) # <---- HANDLER'S CONTEXT IS CHANGING HERE :(
#socket.addListener(name, wrapper)
removeListener: (name, handler) ->
try
obj = #listeners[name]
#socket.removeListener(obj[handler.clientListenerId])
delete obj[handler.clientListenerId]
Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.
If I understand you correctly:
changes context
| n | y |
accepts array n | func() | func.call() |
of arguments y | ???????? | func.apply() |
PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().
Function.prototype.invoke = function(args) {
var i, code = 'this(';
for (i=0; i<args.length; i++) {
if (i) { code += ',' }
code += 'args[' + i + ']';
}
eval(code + ');');
}
Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.
Proof that it works:
function showArgs() {
for (x in arguments) {console.log(arguments[x]);}
}
showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);
Firefox console output:
--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]
Simply put, just assign the this to what you want it to be, which is otherFn:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(otherFn, args);
}
'this' is a reference to your function's context. That's really the point.
If you mean to call it in the context of a different object like this:
otherObj.otherFn(args)
then simply substitute that object in for the context:
otherObj.otherFn.apply(otherObj, args);
That should be it.
If you bind the function to an object and you use everywhere the bound function, you can call apply with null, but still get the correct context
var Person = function(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log("Name: " + this.name);
}
var bob = new Person("Bob");
bob.printName.apply(null); //window.name
bob.printName.bind(bob).apply(null); //"Bob"
One way that you can work around the change of context that can happen in JavaScript when functions are called, is to use methods that are part of the object's constructor if you need them to be able to operate in a context where this is not going to mean the parent object, by effectively creating a local private variable to store the original this identifier.
I concede that - like most discussions of scope in JavaScript - this is not entirely clear, so here is an example of how I have done this:
function CounterType()
{
var counter=1;
var self=this; // 'self' will now be visible to all
var incrementCount = function()
{
// it doesn't matter that 'this' has changed because 'self' now points to CounterType()
self.counter++;
};
}
function SecondaryType()
{
var myCounter = new CounterType();
console.log("First Counter : "+myCounter.counter); // 0
myCounter.incrementCount.apply(this);
console.log("Second Counter: "+myCounter.counter); // 1
}
These days you can use rest parameters:
function fn(...args) {
otherFn(...args);
}
The only downside is, if you want to use some specific params in fn, you have to extract it from args:
function fn(...args) {
let importantParam = args[2]; //third param
// ...
otherFn(...args);
}
Here's an example to try (ES next version to keep it short):
// a one-line "sum any number of arguments" function
const sum = (...args) => args.reduce((sum, value) => sum + value);
// a "proxy" function to test:
var pass = (...args) => sum(...args);
console.log(pass(1, 2, 15));
I'm not going to accept this as an answer, as I'm still hoping for something more suitable. But here's the approach I'm using right now based upon the feedback on this question so far.
For any class that will be calling Client.prototype.addListener or Client.prototype.removeListener, I did added the following code to their constructor:
class ExampleClass
constructor: ->
# ...
for name, fn of this
this[name] = fn.bind(this) if typeof(fn) == 'function'
message: (recipient, body) ->
# ...
broadcast: (body) ->
# ...
In the above example, message and broadcast will always be bound to the new ExampleClass prototype object when it's instantiated, allowing the addListener code in my original question to work.
I'm sure some of you are wondering why I didn't just do something like the following:
example = new ExampleClass
client.addListener('message', example.bind(example))
# ...
client.removeListener('message', example.bind(example))
The problem is that every time .bind( ) is called, it's a new object. So that means that the following is true:
example.bind(example) != example.bind(example)
As such, the removeListener would never work successfully, thus my binding the method once when the object is instantiated.
Since you seem to want to be using the bind function as it is defined in Javascript 1.8.5, and be able to retrieve the original this object you pass the bind function, I recommend redefining the Function.prototype.bind function:
Function.prototype.bind = function (oThis) {
if (typeof this !== "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 && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
/** here's the additional code **/
fBound.getContext = function() {
return oThis;
};
/**/
return fBound;
};
Now you can retrieve the original context that you called the bind function with:
function A() {
return this.foo+' '+this.bar;
}
var HelloWorld = A.bind({
foo: 'hello',
bar: 'world',
});
HelloWorld(); // returns "hello world";
HelloWorld.getContext(); // returns {foo:"hello", bar:"world"};
I was just reminded of this question after a long time. Looking back now, I think what I was really trying to accomplish here was something similar to how the React library works with its automatic binding.
Essentially, each function is a wrapped bound function being called:
function SomeClass() {
};
SomeClass.prototype.whoami = function () {
return this;
};
SomeClass.createInstance = function () {
var obj = new SomeClass();
for (var fn in obj) {
if (typeof obj[fn] == 'function') {
var original = obj[fn];
obj[fn] = function () {
return original.apply(obj, arguments);
};
}
}
return obj;
};
var instance = SomeClass.createInstance();
instance.whoami() == instance; // true
instance.whoami.apply(null) == instance; // true
Just push properties directly to the function's object and call it with it's own "context".
function otherFn() {
console.log(this.foo+' '+this.bar); // prints: "hello world" when called from rootFn()
}
otherFn.foo = 'hello';
otherFn.bar = 'world';
function rootFn() {
// by the way, unless you are removing or adding elements to 'arguments',
// just pass the arguments object directly instead of casting it to Array
otherFn.apply(otherFn, arguments);
}

Javascript's "this" pointing to wrong object inside lambda given to array.map

function myClass() {
this.nums = [1,2,3];
this.divisor = 2;
}
myClass.prototype.divideNumsByDivisor = function(){
return this.nums.map(function(num) {
return num*this.divisor;
});
}
myClass.divideNumsByDivisor() was suposed to multiply each number on it's member variable nums to the value on it's member variable divisor.
This is not working because the function function(num) { return num*this.divisor; } is pointing this to a wrong object.
According to MDN, the 2nd argument to .map(fn, thisArg) is what you want the this ptr to be set to when the callback function is called and it will be set to the global object (e.g window) if you don't pass the 2nd argument.
So, you can make your example work like this:
function myClass() { this.nums = [1,2,3]; this.divisor = 2; }
myClass.prototype.divideNumsByDivisor = function(){
return this.nums.map(function(num) { return num*this.divisor; }, this);
}
You need to define a reference to your instance in the scope then get it later inside a different instance. Update your method to this
myClass.prototype.divideNumsByDivisor = function(){
var me = this;
return this.nums.map(function(num) { return num*me.divisor; });
}

JavaScript: invoke function or call a property via reflection

Is there a way to call a function (or a property) on an object via reflection, in JavaScript?
Lets say that during run-time, my code has already determined that objectFoo indeed has a property called 'bar'. Now that my code knows that, the next thing I want to do is invoke that. Normally i would do this: var x = objectFoo.bar. But 'bar' was determined at run time, so I need to invoke it using reflection.
In JavaScript, object methods are really just properties containing functions. Like all properties, you can refer to them using associative array syntax:
var x = { 'a': 1 };
x.a += 1;
x['a'] += 1;
console.log(x.a);
Output is: 3.
So if you have the name of a method you want to invoke on myObject:
var methodName = 'myMethod';
// Invoke the value of the 'myMethod' property of myObject as a function.
myObject[methodName]();
EVAL:
http://www.w3schools.com/jsref/jsref_eval.asp
Eval will allow you to run any javascript code by passing in a string and having the javascript engine evaluate it as javascript code.
If you mean that you want to first search a list properties of an object, then look at this:
var o = {}
for(att in o){
alert(o[att]);
}
If you do this, you can even set the property's value by accessing it as if it were an array (all objects are actually associative arrays).
obj["propertyName"] = "new value";
obj["MethodName"]();
Create object (invoke constructor) via reflection:
SomeClass = function(arg1, arg2) {
console.log('Your reflection');
}
ReflectUtil.newInstance('SomeClass', 5, 7);
and implementation:
var ReflectUtil = {};
/**
* #param strClass:
* class name
* #param optionals:
* constructor arguments
*/
ReflectUtil.newInstance = function(strClass) {
var args = Array.prototype.slice.call(arguments, 1);
var clsClass = eval(strClass);
function F() {
return clsClass.apply(this, args);
}
F.prototype = clsClass.prototype;
return new F();
};
Create a register object:
var funcRegister = {};
Create a function to call the other:
var callReflectionFunc = function(type, obj) {
var func = false;
if(funcRegister[type])
func = funcRegister[type](obj);
return func;
}
Populate your register with functions:
funcRegister['yourtype1'] = function(obj) {
console.log('your type 2');
return obj;
}
funcRegister['yourtype2'] = function(obj) {
console.log('your type 2');
return obj;
}
Then call it with your type and an object where you can put your args
callReflectionFunc(type, obj);

Categories

Resources